/* =========================================================
 * Saona Agent Panel — Premium UI (tokens-based, dark mode ready)
 * ========================================================= */

*, *::before, *::after { box-sizing: border-box; }

/* `hidden` oculta SIEMPRE. El atributo solo vale como el `display: none` del
   agente de usuario, así que cualquier clase con `display` propio le ganaba y el
   elemento salía a la vista. Se iba parcheando clase a clase (`.field[hidden]`,
   `.cls-aviso[hidden]`…) y cada pantalla nueva volvía a caer: el 29-sep la de
   «Nueva incidencia» enseñaba desde que se abría el aviso «No nos has dicho qué
   falla» (desde el 17-sep) y una caja vacía con «Cambiar» (desde el 14-sep), y
   en Ayuda el botón de limpiar la búsqueda. Una regla para todas; las de cada
   clase se quedan, no estorban. */
[hidden] { display: none !important; }

html {
  scroll-behavior: smooth;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  margin: 0;
  padding: 0;
  font-family: var(--font-sans);
  letter-spacing: var(--tracking-normal);
  color: var(--color-fg);
  background: var(--color-bg);
  min-height: 100dvh;
  overflow-x: hidden;
  transition: background var(--duration-base), color var(--duration-base);
}

/* Fondo liso: el degradado de manchas de color era lo que más ruido metía. */
body::before { content: none; }

::selection { background-color: var(--color-accent); color: var(--color-accent-fg); }
::-webkit-scrollbar { width: 7px; height: 7px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--color-accent-soft);
  border-radius: var(--radius-pill);
}
::-webkit-scrollbar-thumb:hover { background: var(--color-accent); }

:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* ── App shell layout ── */
.app-shell {
  display: grid;
  grid-template-columns: var(--sidebar-width) 1fr;
  min-height: 100dvh;
}
.app-shell.collapsed { grid-template-columns: 72px 1fr; }
@media (max-width: 768px) {
  .app-shell { grid-template-columns: 1fr; }
  .app-sidebar.mobile-hidden { display: none; }
}

/* ── Sidebar ── */
.app-sidebar {
  background: var(--color-surface);
  border-right: 1px solid var(--color-border);
  box-shadow: 4px 0 24px rgb(var(--sombra-tinta) / 0.06);
  border-radius: 0 var(--radius-2xl) var(--radius-2xl) 0;
  padding: 18px 14px;
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100dvh;
  z-index: var(--z-sticky);
}

.app-logo {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 22px;
  padding: 0 4px;
  text-decoration: none;
  color: inherit;
}
.app-logo .logo-mark {
  width: 38px; height: 38px;
  border-radius: 11px;
  background: var(--color-accent);
  color: var(--color-accent-fg);
  display: flex; align-items: center; justify-content: center;
  font-size: 17px; font-weight: var(--weight-bold); letter-spacing: -0.04em;
  box-shadow: var(--shadow-glow);
  flex-shrink: 0;
  transition: transform var(--duration-slow) var(--ease-out), box-shadow var(--duration-slow);
}
.app-logo:hover .logo-mark {
  transform: scale(1.06) rotate(5deg);
  box-shadow: 0 6px 22px rgb(var(--sombra-tinta) / 0.55);
}
.app-logo .logo-text { line-height: 1.1; }
.app-logo .logo-title { font-weight: var(--weight-bold); font-size: var(--text-lg); letter-spacing: var(--tracking-tight); color: var(--color-fg); }
.app-logo .logo-sub { font-size: var(--text-xs); color: var(--color-fg-tertiary); letter-spacing: var(--tracking-normal); }

/* ── La navegación scrollea; la barra, no ──
 * La barra mide `100dvh` y el menú de un admin son trece entradas. En una
 * ventana baja —un portátil, o el navegador con las herramientas abiertas— el
 * menú no cabía y, al no haber `overflow`, lo que sobraba se pintaba FUERA de
 * la barra: «Usuarios», «Grupos de locales» y «Plantillas» quedaban sobre el
 * papel, con el color claro del texto de la barra, casi ilegibles.
 *
 * `min-height: 0` es la mitad del arreglo y la que no se ve: un hijo de un flex
 * en columna no baja de su altura de contenido salvo que se le diga, así que
 * sin esto el `overflow` no llega a activarse nunca y el menú sigue creciendo.
 *
 * `overscroll-behavior` es para el cajón del móvil: al llegar al final de la
 * lista, el gesto se queda en la lista en vez de arrastrar la página de detrás. */
.app-nav {
  display: flex; flex-direction: column; gap: 2px;
  flex: 1; min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Hueco para la barra de scroll, para que no se coma el texto al aparecer. */
  margin-right: -6px; padding-right: 6px;
  scrollbar-width: thin;
  scrollbar-color: var(--color-border-strong) transparent;
}
.app-nav::-webkit-scrollbar { width: 6px; }
.app-nav::-webkit-scrollbar-thumb {
  background: var(--color-border-strong); border-radius: var(--radius-pill);
}
.app-nav::-webkit-scrollbar-track { background: transparent; }
.app-nav .nav-group-label {
  text-transform: uppercase;
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-wide);
  color: var(--color-fg-muted);
  font-weight: var(--weight-semibold);
  padding: 12px 12px 6px;
}
.nav-item {
  display: flex; align-items: center; gap: 11px;
  padding-block: 10px;
  padding-inline: 12px;
  /* En el escritorio, el mínimo del ratón y no el del dedo: con 44 px por
     entrada el menú de seis herramientas se sale por abajo. En el cajón del
     móvil sube a 44 (ver el bloque de zonas de toque, al final). */
  min-height: var(--toque-raton);
  border-radius: var(--radius-md);
  color: var(--color-fg-secondary);
  text-decoration: none;
  font-size: var(--text-md);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-normal);
  transition: all var(--duration-base) var(--ease-out);
  border: 1px solid transparent;
  position: relative;
  animation: navFadeIn 350ms ease both;
}
.nav-item:nth-child(1) { animation-delay: 40ms; }
.nav-item:nth-child(2) { animation-delay: 80ms; }
.nav-item:nth-child(3) { animation-delay: 120ms; }
.nav-item:nth-child(4) { animation-delay: 160ms; }
.nav-item:nth-child(5) { animation-delay: 200ms; }
.nav-item:hover {
  background: var(--color-accent-softer);
  color: var(--color-accent);
}
.nav-item.active {
  background: var(--color-accent-soft);
  color: var(--color-accent);
  font-weight: var(--weight-semibold);
  border-color: var(--color-accent-soft);
}
.nav-item .icon { width: 18px; height: 18px; flex-shrink: 0; }

@keyframes navFadeIn {
  from { opacity: 0; transform: translateX(-6px); }
  to   { opacity: 1; transform: translateX(0); }
}

.app-sidebar-footer {
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--color-border);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* ── Theme switcher ── */
.theme-switcher {
  display: inline-flex;
  background: var(--color-surface-muted);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  padding: 3px;
  gap: 2px;
}
.theme-switcher button {
  background: transparent;
  border: 0;
  padding: 5px 8px;
  /* Cuadrados de 44 y no «tres iconos apretados»: es el control que más se
     falla, porque el que lo busca lo busca de noche y con una mano. */
  min-width: var(--toque-min);
  min-height: var(--toque-min);
  border-radius: var(--radius-pill);
  color: var(--color-fg-tertiary);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: all var(--duration-fast);
}
.theme-switcher button:hover { color: var(--color-fg); background: var(--color-surface-strong); }
.theme-switcher button.is-active {
  background: var(--color-bg-elevated);
  color: var(--color-accent);
  box-shadow: var(--shadow-1);
}
.theme-switcher .icon { width: 14px; height: 14px; }

/* ── User card ── */
.user-card {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-md);
  background: var(--color-surface-muted);
}
.user-card .avatar {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: var(--color-accent);
  color: var(--color-accent-fg);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--text-base); font-weight: var(--weight-bold);
  flex-shrink: 0;
}
.user-card .user-info { flex: 1; min-width: 0; }
.user-card .user-name { font-size: var(--text-base); font-weight: var(--weight-semibold); color: var(--color-fg); }
/* El nombre es el enlace a «Mi cuenta» (2026-10-16): se lee como el nombre de
   siempre y se subraya al pasar. */
.user-card a.user-cuenta { display: block; text-decoration: none; }
.user-card a.user-cuenta:hover, .user-card a.user-cuenta:focus-visible { text-decoration: underline; }
.user-card .user-role { font-size: var(--text-xs); color: var(--color-fg-tertiary); }
.user-card .logout-btn {
  /* Salir de la cuenta compartida del local es cosa de todos los días: 44×44,
     como cualquier otro icono-botón. */
  width: var(--toque-min); height: var(--toque-min);
  flex-shrink: 0;
  border-radius: var(--radius-sm);
  border: none;
  background: transparent;
  color: var(--color-fg-tertiary);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: all var(--duration-fast);
  text-decoration: none;
}
.user-card .logout-form { margin: 0; display: flex; flex-shrink: 0; }
.user-card .logout-btn:hover { background: var(--color-danger-soft); color: var(--color-danger); }

/* ── Main content ── */
.app-main {
  padding: 28px 36px;
  max-width: 1600px;
  width: 100%;
  margin: 0 auto;
  animation: pageIn 350ms var(--ease-out);
}
@keyframes pageIn {
  from { opacity: 0; transform: translateY(12px); filter: blur(2px); }
  to   { opacity: 1; transform: translateY(0); filter: blur(0); }
}
@media (max-width: 768px) {
  .app-main { padding: 16px 14px; }
}

/* ── Page header ── */
.page-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 26px;
  flex-wrap: wrap; gap: var(--space-3);
}
.page-title {
  font-size: var(--text-3xl); font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-tight); color: var(--color-fg);
}
.page-subtitle {
  font-size: var(--text-base); color: var(--color-fg-tertiary); margin-top: 2px;
}

/* La cabecera de la ficha del ticket.

   `.page-header` ya envuelve, pero el bloque del título llevaba `flex: 1;
   min-width: 0`: un elemento que puede encoger hasta cero NUNCA fuerza el
   salto de línea, así que en un iPhone los tres botones se quedaban en la
   misma fila y al asunto le sobraban veinte píxeles —una palabra por línea—.
   Con una base de 240px no cabe al lado de los botones y baja entero. */
.ficha-cabecera .ficha-titulo { flex: 1 1 240px; min-width: 0; }
.ficha-cabecera .ficha-acciones { display: flex; gap: 6px; flex-wrap: wrap; }
/* Lo que hasta el 2026-10-10 iba en atributos `style` de ticket.html: un
   atributo le gana a cualquier hoja y no dejaba recolocar la cabecera en el
   escritorio (escritorio.css). En el móvil se pinta igual que antes. */
.ficha-cabecera { align-items: flex-start; }
.ficha-cabecera .page-title {
  margin-top: 4px;
  display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap;
}
.ficha-cabecera .ficha-id { color: var(--color-fg-tertiary); font-weight: var(--weight-medium); }
.ficha-cabecera .page-subtitle { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }

/* ── Cards ── */
.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  padding: 18px 20px;
  box-shadow: var(--shadow-1);
  transition: box-shadow var(--duration-base), transform var(--duration-base);
  position: relative;
}
.card::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 0 0 1px rgba(255, 255, 255, 0.22);
}
html[data-theme="dark"] .card::after {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    inset 0 0 0 1px rgba(255, 255, 255, 0.04);
}
.card-hover:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-2);
}
.card-title {
  font-size: var(--text-base); font-weight: var(--weight-semibold); color: var(--color-fg);
  display: flex; align-items: center; gap: var(--space-2);
  margin-bottom: 14px;
  letter-spacing: var(--tracking-snug);
}
.card-title .icon { width: 16px; height: 16px; color: var(--color-fg-tertiary); }

/* ── Tables ── */
.t-modern {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--text-base);
}
.t-modern thead th {
  text-align: left;
  padding: 8px 10px;
  font-weight: var(--weight-semibold);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--color-fg-muted);
  border-bottom: 1px solid var(--color-border);
}
.t-modern tbody td {
  padding: 10px 10px;
  border-bottom: 1px solid var(--color-border-soft);
}
.t-modern tbody tr:last-child td { border-bottom: none; }
.t-modern tbody tr { transition: background var(--duration-fast); }
.t-modern tbody tr:hover { background: var(--color-accent-softer); }
.t-modern .mono { font-family: var(--font-mono); font-size: var(--text-sm); }
.t-modern .text-xs { font-size: var(--text-xs); }
.t-modern .text-secondary { color: var(--color-fg-tertiary); }
.t-empty {
  text-align: center;
  padding: 24px;
  color: var(--color-fg-muted);
  font-size: var(--text-base);
}

/* ── Badges ── */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px;
  border-radius: var(--radius-sm);
  font-size: var(--text-xs); font-weight: var(--weight-semibold);
  letter-spacing: -0.005em;
  white-space: nowrap;
}
.badge.badge-open    { background: var(--color-warning-soft); color: var(--color-warning-fg); }
.badge.badge-pending { background: var(--color-info-soft);    color: var(--color-info-fg); }
.badge.badge-hold    { background: var(--color-surface-muted); color: var(--color-fg-secondary); }
.badge.badge-new     { background: var(--color-accent-soft);  color: var(--color-accent); }
.badge.badge-solved,
.badge.badge-resolved{ background: var(--color-success-soft); color: var(--color-success-fg); }
.badge.badge-closed  { background: var(--color-surface-muted); color: var(--color-fg-secondary); }
/* Cuentas de prueba de «Ver como…» en /admin: el único sitio donde salen. */
.badge.badge-prueba  { background: var(--color-warning-soft); color: var(--color-warning-fg); }
.badge.badge-admin   { background: var(--color-accent-soft);  color: var(--color-accent); }
.badge.badge-viewer  { background: var(--color-info-soft);    color: var(--color-info-fg); }
.badge.badge-handoff { background: var(--color-warning-soft); color: var(--color-warning-fg); }
.badge.badge-bot     { background: var(--color-accent-soft);  color: var(--color-accent); }
.badge.badge-bot_temporary { background: var(--color-accent-soft); color: var(--color-accent); }
.badge.badge-agent   { background: var(--color-accent-soft);  color: var(--color-accent); }
.badge.badge-alta    { background: var(--color-danger-soft);  color: var(--color-danger-fg); }
.badge.badge-media   { background: var(--color-warning-soft); color: var(--color-warning-fg); }
.badge.badge-baja    { background: var(--color-surface-muted); color: var(--color-fg-secondary); }
/* Estados de Personal (peticiones a Nexus). Mismos tokens que el resto, así
   que se ven igual de bien en claro y en oscuro. Un .badge sin modificador
   no tiene ni fondo ni color: en oscuro desaparecía. */
.badge.badge-espera  { background: var(--color-info-soft);    color: var(--color-info-fg); }
/* Lo pendiente («sin leer», «por validar», lo que espera una acción tuya):
   el ocre de la marca con texto azul noche (guía). Solo esto va en ocre. */
.badge.badge-accion,
.badge.badge-pendiente { background: var(--aviso); color: var(--texto-sobre-aviso); }
.badge.badge-curso   { background: var(--color-accent-soft);  color: var(--color-accent); }
.badge.badge-cerrada { background: var(--color-surface-muted); color: var(--color-fg-secondary); }
/* La opinión del local en la entrevista (entrevista-local/1, 17-oct). */
.badge.badge-apto    { background: var(--color-success-soft); color: var(--color-success-fg); }
.badge.badge-no-apto { background: var(--color-surface-muted); color: var(--color-fg-secondary); }
/* «sin responder»: tiene que leerse sin gritar. Es un dato, no una alarma;
   la alarma ya la da el SLA que va justo al lado. */
.badge.badge-suave   { background: var(--color-surface-muted); color: var(--color-fg-secondary);
                       font-weight: var(--weight-medium); }

html[data-theme="dark"] .badge.badge-admin   { color: var(--color-accent); background: var(--color-accent-soft); }
html[data-theme="dark"] .badge.badge-bot_temporary { color: var(--color-accent); background: var(--color-accent-soft); }

/* ── Forms ── */
.field { display: block; }
/* Un `display` propio le gana a `[hidden]`, que solo vale como el `display:
   none` del agente de usuario (la piedra de siempre: ver `.cls-aviso[hidden]`).
   Sin esto, los campos que se enseñan con JavaScript salen desde el primer
   momento: en «Nueva incidencia» se veían «¿Quién lo tiene que ver?» y «¿De
   qué pedido hablamos?» como cajas vacías antes de elegir nada. */
.field[hidden] { display: none; }
.field-label {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--color-fg-muted);
  margin-bottom: 5px;
  display: block;
}
.field-input, .field-select, textarea.field-input {
  width: 100%;
  padding: 10px 12px;
  font-size: var(--text-base);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-bg-elevated);
  color: var(--color-fg);
  transition: border-color var(--duration-fast), box-shadow var(--duration-fast), background var(--duration-fast);
  font-family: inherit;
}
.field-input:focus, .field-select:focus, textarea.field-input:focus {
  outline: none;
  border-color: var(--color-accent);
  box-shadow: 0 0 0 3px var(--color-accent-soft);
}
.field-input.mono { font-family: var(--font-mono); font-size: var(--text-sm); }

/* Los controles de formulario, a 44 px también en el ordenador.
 *
 * El `textarea` se queda fuera del mínimo a propósito: ya trae el suyo, que es
 * mayor, y meterlo aquí solo serviría para pisarlo el día que alguien cambie
 * el orden de las reglas. */
.field-input:not(textarea), .field-select,
.filter-search, .inbox-search input {
  min-height: var(--toque-min);
}

/* Red de seguridad para los que no llevan nuestras clases: en las fichas hay
 * `select` e `input` con el `style=` puesto a mano —la urgencia del ticket, el
 * buscador de plantillas— y eran justo los que medían 28 px.
 *
 * Con `:where()`, que no puntúa: cualquier otra regla la gana sin pelear. Hace
 * falta porque aquí hay controles que se esconden en 1 px para que sigan
 * cogiendo el foco (`.ver-esperando-check`, el interruptor de avisos), y un
 * mínimo que se les impusiera les pondría una caja invisible encima de lo que
 * se quiere pulsar. Los de fichero quedan fuera por lo mismo
 * (`.sol-fotos-input` vive detrás de un botón dibujado). */
:where(input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):not([type="file"]),
       select) {
  min-height: var(--toque-min);
}

/* La casilla no puede medir 44 px sin deformar las rejillas de permisos y de
 * locales, así que lo que se pulsa es la ETIQUETA —que sí lleva el mínimo, más
 * abajo— y la casilla sube a 20 px para que se vea y se acierte. Nada de
 * `transform: scale()`: agranda el dibujo, no el área que recoge el toque. */
:where(input[type="checkbox"], input[type="radio"]) {
  width: 20px; height: 20px;
  flex-shrink: 0;
  accent-color: var(--color-accent);
}

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding-block: 10px;
  padding-inline: 14px;
  /* Un botón es la acción: los 44 px van en los dos tamaños de pantalla. */
  min-height: var(--toque-min);
  font-size: var(--text-base); font-weight: var(--weight-semibold);
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  cursor: pointer;
  transition: all var(--duration-fast);
  text-decoration: none;
  letter-spacing: var(--tracking-normal);
  font-family: inherit;
  white-space: nowrap;
}
.btn:disabled { opacity: 0.55; cursor: not-allowed; }
.btn-primary {
  background: var(--primario);
  color: var(--texto-sobre-primario);
  box-shadow: 0 1px 3px rgb(var(--sombra-tinta) / 0.20);
}
.btn-primary:hover:not(:disabled) {
  background: var(--color-accent-hover);
  box-shadow: 0 3px 10px rgb(var(--sombra-tinta) / 0.26);
  transform: translateY(-1px);
}
.btn-secondary {
  background: var(--color-bg-elevated);
  color: var(--color-fg-secondary);
  border-color: var(--color-border-strong);
}
.btn-secondary:hover:not(:disabled) {
  background: var(--color-surface-muted);
  border-color: var(--color-border-strong);
  color: var(--color-fg);
}
.btn-ghost {
  background: transparent;
  color: var(--color-fg-secondary);
}
.btn-ghost:hover:not(:disabled) { background: var(--color-surface-muted); color: var(--color-fg); }
.btn-danger { background: var(--color-danger); color: var(--color-fg-inverse); }
.btn-danger:hover:not(:disabled) { background: var(--color-danger); }
.btn-warning { background: var(--aviso); color: var(--texto-sobre-aviso); }
.btn-warning:hover:not(:disabled) { background: var(--color-warning-fg); }
/* `btn-sm` baja la letra y el relleno lateral, NO el alto: «pequeño» era la
   excusa por la que «Marcar leídos» medía 26 px. */
.btn-sm { padding-block: 6px; padding-inline: 10px; font-size: var(--text-sm); }
.btn .icon { width: 14px; height: 14px; }

/* Los botones que solo llevan icono: cuadrados y de 44 px de verdad.
 *
 * Un icono de 14 px con 5 de relleno daba 36×26 —las flechas de la ficha, el
 * embudo de la cola—, y ahí no se apunta: se acierta por suerte. `btn-icon` es
 * el nombre para los que vengan; los de `id` están listados porque nacieron
 * antes que la clase. */
.btn-icon,
#prevTicket, #nextTicket, #btnFilters, #btnRefresh {
  min-width: var(--toque-min);
  min-height: var(--toque-min);
  padding-inline: 10px;
}

/* ── Login ── */
.login-shell {
  min-height: 100dvh;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
}
.login-card {
  width: 100%;
  max-width: 420px;
  background: var(--color-surface-strong);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-2xl);
  padding: 32px 30px;
  box-shadow: var(--shadow-3);
  animation: pageIn 400ms var(--ease-out);
}
.login-logo {
  display: flex; flex-direction: column; align-items: center;
  margin-bottom: 26px;
}
.login-logo .logo-mark {
  width: 56px; height: 56px;
  border-radius: 16px;
  background: var(--color-accent);
  color: var(--color-accent-fg);
  display: flex; align-items: center; justify-content: center;
  font-size: 24px; font-weight: var(--weight-bold); letter-spacing: -0.04em;
  box-shadow: 0 8px 24px rgb(var(--sombra-tinta) / 0.35);
  margin-bottom: 14px;
}
.login-logo h1 {
  font-size: var(--text-xl); font-weight: var(--weight-bold);
  margin: 0; letter-spacing: var(--tracking-tight); color: var(--color-fg);
}
.login-logo p { font-size: var(--text-sm); color: var(--color-fg-tertiary); margin: 2px 0 0; }

/* ── Misc helpers ── */
.text-mono { font-family: var(--font-mono); }
.text-secondary { color: var(--color-fg-tertiary); }
.text-tertiary { color: var(--color-fg-muted); }
.divider { height: 1px; background: var(--color-border); margin: 14px 0; }

.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)); gap: 14px; }
.grid-3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 14px; }
.grid-4 { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; }

.fade-in { animation: pageIn 350ms var(--ease-out); }

kbd {
  font-family: var(--font-mono);
  font-size: 12px;
  background: var(--color-surface-muted);
  border: 1px solid var(--color-border);
  padding: 1px 5px;
  border-radius: 4px;
  color: var(--color-fg-secondary);
  white-space: nowrap;
}

/* ───────── Inbox: ticket row premium (Plan 02) ───────── */
.inbox-card {
  padding: 0;
  overflow: hidden;
  position: relative;
  background: var(--color-surface);
  box-shadow: var(--shadow-1), 0 0 0 1px var(--color-border);
  border: 0;
}
.inbox-card::after {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 0 0 1px rgba(255, 255, 255, 0.18);
  z-index: 1;
}
html[data-theme="dark"] .inbox-card::after {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    inset 0 0 0 1px rgba(255, 255, 255, 0.04);
}
/* ── El reparto de anchos de la cola (escritorio) ──

   Las TRES rejillas de aquí abajo —cabecera, fila y esqueleto del cargando—
   tienen que decir exactamente lo mismo o las columnas bailan al llegar la
   lista.

   Por qué estos números (2026-09-21): el asunto es la ÚNICA columna elástica
   (`minmax(0, 1fr)`) y todo lo demás está tasado al ancho de su dato —un
   nombre de local, una pastilla de plazo, un badge de estado—, porque el
   asunto es el único texto que cuenta de qué va la incidencia. Antes las
   fijas se llevaban 812 px de los 916 que tiene la fila en un portátil de
   1280, y al asunto le quedaban 102: «Gran…», «Alam…», «Gran…» (captura de
   Victor, 2026-09-21). Ahora las fijas suman 756 con el departamento ya en su
   propia columna, y lo que sobra es del asunto. Si hay que recortar algo es el
   local o la categoría, que van con puntos suspensivos y se saben de memoria;
   nunca el asunto. */
.inbox-thead {
  display: grid;
  grid-template-columns: 32px 46px minmax(0, 1fr) 100px 86px 108px 82px 82px 110px 40px;
  gap: 8px;
  align-items: center;
  padding: 12px 18px;
  background: var(--color-surface-muted);
  border-bottom: 1px solid var(--color-border);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--color-fg-muted);
  font-weight: var(--weight-semibold);
  position: sticky; top: 0;
  z-index: 5;
}
.inbox-thead .col-checkbox,
.inbox-thead .col-id { text-align: left; }
/* Una cabecera no puede salirse de su columna: una palabra larga se pintaba
   encima de la de al lado y se leía «DEPARTAMENTCATEGORÍA» (2026-09-21). */
.inbox-thead > div { min-width: 0; overflow: hidden; }

.ticket-row {
  display: grid;
  grid-template-columns: 32px 46px minmax(0, 1fr) 100px 86px 108px 82px 82px 110px 40px;
  gap: 8px;
  align-items: center;
  padding: 12px 18px;
  border-bottom: 1px solid var(--color-border-soft);
  text-decoration: none;
  color: inherit;
  transition: background var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out);
  font-size: var(--text-base);
  position: relative;
  z-index: 1;
  animation: rowEnter 320ms var(--ease-out) both;
  animation-delay: calc(var(--row-i, 0) * 24ms);
}
@keyframes rowEnter {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.ticket-row::before {
  content: '';
  position: absolute;
  left: 0; top: 6px; bottom: 6px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: transparent;
  transition: background var(--duration-base), box-shadow var(--duration-base);
}
.ticket-row.is-new::before {
  background: var(--color-accent);
  box-shadow: 0 0 12px rgb(var(--sombra-tinta) / 0.45);
}
.ticket-row.is-urgent::before {
  background: var(--color-danger);
  box-shadow: 0 0 12px rgb(179 55 45 / 0.45);
}
.ticket-row.is-breach::before {
  background: var(--color-danger);
  box-shadow: 0 0 14px var(--color-danger);
  animation: breachPulse 2.4s ease-in-out infinite;
}
.ticket-row.is-warn::before { background: var(--sla-warn); }
@keyframes breachPulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.55; }
}
.ticket-row:hover {
  background: var(--color-accent-softer);
  transform: translateX(2px);
  box-shadow: inset 0 0 0 1px var(--color-accent-soft);
}
.ticket-row.is-flash {
  animation: rowFlash 2000ms var(--ease-out);
}
@keyframes rowFlash {
  0%   { background: var(--color-success-soft); box-shadow: inset 0 0 0 2px var(--color-success); }
  60%  { background: var(--color-success-soft); }
  100% { background: transparent; box-shadow: none; }
}

.ticket-row .col-checkbox input { accent-color: var(--color-accent); cursor: pointer; }
/* 150px y no 90: el estado pasó de «pending» a «Pendiente de un externo» y el
   badge se salía de su columna. Se dice en castellano o se dice corto; se ha
   elegido en castellano, así que la columna se ensancha. */
.ticket-row .col-channel { display: flex; flex-direction: column; gap: 3px; align-items: flex-start; }
.ticket-row .col-channel .badge { max-width: 100%; white-space: normal; text-align: left; }

.local-avatar {
  width: 36px; height: 36px;
  border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  font-weight: var(--weight-bold);
  font-size: var(--text-sm);
  color: var(--crema);
  letter-spacing: 0;
  flex-shrink: 0;
  text-transform: uppercase;
  background: var(--avatar-bg, var(--color-accent));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.30),
    inset 0 -2px 0 rgba(0, 0, 0, 0.10),
    0 1px 3px rgb(var(--sombra-tinta) / 0.12);
  position: relative;
  transition: transform var(--duration-fast) var(--ease-out);
}
.ticket-row:hover .local-avatar { transform: scale(1.05); }

.row-id {
  font-family: var(--font-mono);
  font-weight: var(--weight-semibold);
  color: var(--color-fg-secondary);
  font-size: var(--text-sm);
}
.ticket-row.is-new .row-id { color: var(--color-accent); }

.ticket-row .col-subject {
  display: flex; gap: 10px; align-items: center; min-width: 0;
}
.row-subject { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
/* Dos líneas, también en escritorio (2026-09-21). El recorte a UNA era fijo y
   daba igual el monitor: a 1280 dejaba «Gran…» y a 1920, con setecientos
   píxeles libres, seguía cortando el asunto largo por la mitad. Con dos, un
   asunto que cabe sigue ocupando una sola línea —la fila no crece— y el que no
   cabe se lee entero en vez de terminar en puntos suspensivos. */
.row-subject .subj {
  font-weight: var(--weight-semibold);
  color: var(--color-fg);
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  line-height: 1.3;
}
.row-subject .meta {
  color: var(--color-fg-tertiary);
  font-size: var(--text-xs);
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.row-subject .meta .channel-icon {
  display: inline-flex; align-items: center; gap: 3px;
}
.row-subject .meta .channel-icon .icon { width: 11px; height: 11px; }
.row-subject .meta .sep { color: var(--color-fg-muted); }
/* El «·» lo pone el CSS entre dos piezas, nunca al principio ni al final: así
   una tarjeta sin categoría o sin urgencia no arrastra un punto huérfano, que
   es lo que se veía en el iPhone. */
.row-subject .meta .pieza { display: inline-flex; align-items: center; gap: 4px; }
.row-subject .meta .pieza + .pieza::before {
  content: '·';
  color: var(--color-fg-muted);
}
/* Para lectores de pantalla: el icono de canal solo, sin texto, no dice nada. */
.visualmente-oculto {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.row-local-name {
  color: var(--color-fg);
  font-size: var(--text-sm);
  display: flex; flex-direction: column;
  min-width: 0;
}
.row-local-name .name { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* El departamento tenía columna: la del local, debajo del nombre. Se leía
   «Gran via / IT», como si el departamento fuese parte del sitio, y dejaba la
   columna de al lado a medio usar (Victor, 2026-09-21). */
.row-dept {
  font-size: var(--text-sm);
  color: var(--color-fg-secondary);
  min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.row-cat {
  font-size: var(--text-sm);
  color: var(--color-fg-secondary);
  min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.row-cat .seccion {
  display: block;
  font-size: var(--text-xs);
  color: var(--color-fg-muted);
}

.row-time {
  font-size: var(--text-sm);
  color: var(--color-fg-secondary);
  font-variant-numeric: tabular-nums;
}
.row-time.is-warn { color: var(--sla-warn); font-weight: var(--weight-semibold); }
.row-time.is-breach { color: var(--color-danger); font-weight: var(--weight-semibold); }

.row-sla {
  display: inline-flex; align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.005em;
  white-space: nowrap;
  border: 1px solid transparent;
  font-variant-numeric: tabular-nums;
}
.row-sla .dot {
  width: 6px; height: 6px; border-radius: 50%;
  flex-shrink: 0;
  box-shadow: 0 0 0 2px currentColor;
  opacity: 0.9;
}
.row-sla.sla-safe   { background: var(--color-success-soft); color: var(--color-success-fg); border-color: var(--color-success-soft); }
.row-sla.sla-safe .dot { background: var(--color-success); box-shadow: 0 0 0 0 var(--color-success); }
/* Aquí vivía `.row-sla.sla-soft`. El estado `soft` lo producía el semáforo por
   inactividad de la bandeja, que se retiró el 2026-09-19 (una sola definición
   de SLA, la de las políticas del proveedor), así que ya no llega nunca. */
.row-sla.sla-warn   { background: var(--color-warning-soft); color: var(--sla-warn); border-color: var(--sla-warn); }
html[data-theme="dark"] .row-sla.sla-warn { color: var(--sla-warn); background: var(--color-warning-soft); }
.row-sla.sla-warn .dot { background: var(--sla-warn); box-shadow: 0 0 0 0 var(--sla-warn); }
.row-sla.sla-breach { background: var(--color-danger-soft); color: var(--color-danger-fg); border-color: var(--color-danger); }
.row-sla.sla-breach .dot {
  background: var(--color-danger);
  box-shadow: 0 0 0 0 var(--color-danger);
  animation: dotPulse 1.6s ease-out infinite;
}
@keyframes dotPulse {
  0%   { box-shadow: 0 0 0 0 var(--color-danger); }
  70%  { box-shadow: 0 0 0 6px rgb(179 55 45 / 0); }
  100% { box-shadow: 0 0 0 0 rgb(179 55 45 / 0); }
}

/* ── SLA pills (countdown live) ─────────────────────────────────────
   Reutilizan base visual de .row-sla, añadiendo estados ok/done que
   .row-sla no tenía. */
.sla-pill {
  display: inline-flex; align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.005em;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}
.sla-pill .dot {
  width: 6px; height: 6px; border-radius: 50%;
  flex-shrink: 0;
  opacity: 0.95;
}
/* `sla-safe` es el nombre del contrato (`proveedor.ESTADOS_SLA`); `sla-ok` era
   como lo llamaba el contador antes de la fase 3 y se conserva para el HTML
   ya servido. */
.sla-pill.sla-ok,
.sla-pill.sla-safe {
  background: var(--color-success-soft);
  color: var(--color-success-fg);
  border-color: var(--color-success-soft);
}
.sla-pill.sla-ok .dot,
.sla-pill.sla-safe .dot { background: var(--color-success); }
.sla-pill.sla-warn {
  background: var(--color-warning-soft);
  color: var(--sla-warn);
  border-color: var(--sla-warn);
}
html[data-theme="dark"] .sla-pill.sla-warn { color: var(--sla-warn); background: var(--color-warning-soft); }
.sla-pill.sla-warn .dot { background: var(--sla-warn, var(--sla-warn)); }
.sla-pill.sla-breach {
  background: var(--color-danger-soft);
  color: var(--color-danger-fg);
  border-color: var(--color-danger);
}
.sla-pill.sla-breach .dot {
  background: var(--color-danger);
  animation: dotPulse 1.6s ease-out infinite;
}
.sla-pill.sla-done {
  background: rgb(47 107 86 / 0.10);
  color: var(--color-success-fg);
  border-color: rgb(47 107 86 / 0.30);
}
.sla-pill.sla-done .dot { background: var(--color-success); }
/* Sin plazo POR DECISIÓN (esperando a un externo, 2026-11-04): neutro. Ni
   verde —diría «va bien de tiempo»— ni rojo: no hay tiempo que medir. */
.sla-pill.sla-none,
.row-sla.sla-none {
  background: transparent;
  color: var(--color-fg-muted);
  border-color: var(--color-border);
}
.sla-pill.sla-none .dot,
.row-sla.sla-none .dot { background: var(--color-fg-muted); }

.row-actions {
  display: flex; gap: 4px;
  opacity: 0;
  transition: opacity var(--duration-fast);
  justify-content: flex-end;
}
.ticket-row:hover .row-actions { opacity: 1; }
.row-actions .icon-btn {
  /* El mínimo del ratón y no el del dedo: estos tres solo aparecen al pasar por
     encima (`.row-actions` nace en `opacity: 0`) y en el móvil la columna
     entera se esconde, así que a este nunca le llega un dedo. Su columna de la
     rejilla mide 40 px y lleva UN botón, «copiar ID». Hasta el 2026-10-06
     llevaba también «ver» en 38 px (34 en portátil): los aplastaba a 15 px de
     ancho. «Ver» sobraba: la fila entera ya es un enlace al ticket. Ensanchar
     la columna para los dos le quitaba 54 px al asunto, que no se recorta. */
  width: var(--toque-raton); height: var(--toque-raton);
  flex-shrink: 0;
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border);
  background: var(--color-bg-elevated);
  color: var(--color-fg-tertiary);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: all var(--duration-fast);
  text-decoration: none;
}
.row-actions .icon-btn:hover {
  color: var(--color-accent);
  border-color: var(--color-accent);
  background: var(--color-accent-softer);
}
.row-actions .icon-btn .icon { width: 13px; height: 13px; }

.is-new-pill {
  display: inline-flex;
  background: var(--color-accent);
  color: var(--color-accent-fg);
  font-size: 12px;
  font-weight: var(--weight-bold);
  letter-spacing: 0.05em;
  padding: 1px 5px;
  border-radius: 3px;
  text-transform: uppercase;
  margin-right: 4px;
}

/* ── Inbox header / control bar ── */
.inbox-controls {
  display: flex; flex-direction: column; gap: 12px;
  margin-bottom: 14px;
}
.inbox-metrics {
  display: flex; gap: 8px;
  flex-wrap: wrap;
  align-items: center;
}
/* KPI informativo (no filtra): mismo look que metric-pill pero sin interacción */
.summary-stat {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 14px;
  border-radius: var(--radius-pill);
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--color-fg-secondary);
  cursor: default;
  user-select: none;
}
.summary-stat .value { font-weight: var(--weight-bold); color: var(--color-fg); }
.summary-stat.summary-stat-total { border-style: solid; background: var(--color-surface); }
.summary-stat.summary-stat-total .value { font-size: 1.05em; }
.summary-stat.tone-danger { border-color: var(--color-danger); }
.summary-stat.tone-danger .value { color: var(--color-danger); }
/* Separador visual entre desglose de estado y KPIs de atención */
.metrics-sep {
  width: 1px; align-self: stretch; min-height: 20px;
  background: var(--color-border); margin: 0 4px;
}
.metric-pill {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 14px;
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--color-fg-secondary);
  box-shadow: var(--shadow-1);
  transition: all var(--duration-base) var(--ease-out);
  cursor: pointer;
  user-select: none;
  position: relative;
  overflow: hidden;
}
.metric-pill::before {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.55);
}
html[data-theme="dark"] .metric-pill::before { box-shadow: inset 0 1px 0 rgba(255,255,255,0.06); }
.metric-pill .label { color: var(--color-fg-tertiary); font-size: var(--text-xs); }
/* El rótulo corto es solo del móvil: el porqué, en el bloque de la cola en un teléfono. */
.metric-pill .label-corta { display: none; }
.metric-pill .value {
  font-weight: var(--weight-bold);
  color: var(--color-fg);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.metric-pill.tone-danger { border-color: var(--color-danger); background: var(--color-surface); }
.metric-pill.tone-danger .value { color: var(--color-danger-fg); }
.metric-pill.tone-warning { border-color: var(--color-warning); background: var(--color-surface); }
.metric-pill.tone-warning .value { color: var(--color-warning-fg); }
.metric-pill.tone-success { border-color: var(--color-success); background: var(--color-surface); }
.metric-pill.tone-success .value { color: var(--color-success-fg); }
/* Solo con ratón: en el dedo el `hover` se queda pegado al último botón
   tocado y parecía seleccionado sin estarlo (captura de Victor, 2026-10-10). */
@media (hover: hover) {
  .metric-pill:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-2);
    border-color: var(--color-accent);
  }
}
.metric-pill.is-active {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: var(--color-accent-fg);
  box-shadow: 0 4px 14px rgb(var(--sombra-tinta) / 0.32);
}
.metric-pill.is-active .label,
.metric-pill.is-active .value { color: inherit; }
.metric-pill.tone-danger.is-active { background: var(--color-danger); border-color: var(--color-danger); color: var(--color-fg-inverse); box-shadow: 0 4px 14px rgb(179 55 45 / 0.30); }
.metric-pill.tone-warning.is-active { background: var(--aviso); border-color: var(--aviso); color: var(--texto-sobre-aviso); box-shadow: 0 4px 14px rgb(168 113 26 / 0.30); }
.metric-pill.tone-success.is-active { background: var(--color-success); border-color: var(--color-success); color: var(--color-fg-inverse); box-shadow: 0 4px 14px rgb(47 107 86 / 0.30); }
/* Un botón de verdad (2026-10-10): sin el tipo de letra ni el fondo del
   navegador, y con foco visible para el teclado. */
button.metric-pill { font-family: inherit; line-height: inherit; text-align: left; }
.metric-pill:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
/* A cero se ve apagado pero sigue tocándose: lleva a una lista vacía que lo
   explica. El activo nunca se apaga, aunque se quede a cero. */
.metric-pill.es-cero:not([aria-pressed="true"]) { opacity: 0.55; box-shadow: none; }
.metric-pill.es-cero:not([aria-pressed="true"]) .value { color: var(--color-fg-tertiary); }

.inbox-toolbar {
  display: flex; gap: 10px; align-items: center;
  flex-wrap: wrap;
}
.inbox-search {
  position: relative;
  flex: 1;
  min-width: 220px;
  max-width: 380px;
}
.inbox-search input {
  width: 100%;
  padding: 8px 12px 8px 36px;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  font-size: var(--text-base);
  background: var(--color-bg-elevated);
  color: var(--color-fg);
  font-family: inherit;
  transition: all var(--duration-fast);
}
.inbox-search input:focus {
  outline: none;
  border-color: var(--color-accent);
  box-shadow: 0 0 0 3px var(--color-accent-soft);
}
.inbox-search .icon-search {
  position: absolute;
  left: 11px; top: 50%; transform: translateY(-50%);
  width: 14px; height: 14px;
  color: var(--color-fg-muted);
  pointer-events: none;
}
.inbox-search kbd {
  position: absolute;
  right: 8px; top: 50%; transform: translateY(-50%);
  pointer-events: none;
}

.chip-row { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding-block: 7px;
  padding-inline: 13px;
  /* Escritorio: el mínimo del ratón. En el móvil, 44 (bloque del final). */
  min-height: var(--toque-raton);
  border-radius: var(--radius-campo);   /* guía: chips a 8 */
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--color-fg-secondary);
  cursor: pointer;
  transition: all var(--duration-fast);
  user-select: none;
  text-decoration: none;
}
.chip:hover { border-color: var(--color-accent); color: var(--color-accent); }
.chip.is-active {
  background: var(--color-accent-soft);
  border-color: var(--color-accent);
  color: var(--color-accent);
  font-weight: var(--weight-semibold);
}
.chip .icon { width: 12px; height: 12px; }
.chip .count {
  background: var(--color-surface-muted);
  color: var(--color-fg-tertiary);
  font-weight: var(--weight-semibold);
  padding: 0 5px;
  border-radius: var(--radius-pill);
  font-size: 12px;
  margin-left: 2px;
}
.chip.is-active .count { background: var(--color-accent); color: var(--color-accent-fg); }
.chip.tone-danger.is-active { background: var(--color-danger-soft); border-color: var(--color-danger); color: var(--color-danger-fg); }
.chip.tone-warning.is-active { background: var(--color-warning-soft); border-color: var(--color-warning); color: var(--color-warning-fg); }

.toolbar-spacer { flex: 1; }
.live-indicator {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--text-xs);
  color: var(--color-fg-tertiary);
  font-variant-numeric: tabular-nums;
}
.live-indicator .pulse {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--color-success);
  box-shadow: 0 0 0 0 rgb(47 107 86 / 0.6);
  animation: livePulse 1.6s ease-out infinite;
}
@keyframes livePulse {
  0%   { box-shadow: 0 0 0 0 rgb(47 107 86 / 0.6); }
  70%  { box-shadow: 0 0 0 8px rgb(47 107 86 / 0); }
  100% { box-shadow: 0 0 0 0 rgb(47 107 86 / 0); }
}

/* ── Bulk action bar (flotante) ── */
.bulk-bar {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%) translateY(80px);
  display: flex; align-items: center; gap: 12px;
  padding: 10px 16px;
  background: var(--color-surface-strong);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-3);
  z-index: var(--z-modal);
  font-size: var(--text-base);
  opacity: 0;
  pointer-events: none;
  transition: all 250ms var(--ease-spring);
}
.bulk-bar.is-visible {
  transform: translateX(-50%) translateY(0);
  opacity: 1;
  pointer-events: auto;
}
.bulk-bar .bulk-count {
  font-weight: var(--weight-semibold);
  color: var(--color-fg);
}
.bulk-bar .bulk-actions { display: flex; gap: 6px; }

/* ── View toggle / density ── */
.view-toggle {
  display: inline-flex;
  background: var(--color-surface-muted);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 3px;
  gap: 2px;
}
.view-toggle button {
  background: transparent;
  border: 0;
  padding: 5px 10px;
  min-width: var(--toque-raton);
  min-height: var(--toque-raton);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--color-fg-tertiary);
  cursor: pointer;
  display: inline-flex; align-items: center; gap: 4px;
  font-family: inherit;
  transition: all var(--duration-fast);
}
.view-toggle button:hover { color: var(--color-fg); }
.view-toggle button.is-active {
  background: var(--color-bg-elevated);
  color: var(--color-accent);
  box-shadow: var(--shadow-1);
}
.view-toggle .icon { width: 14px; height: 14px; }

.app-shell.density-compact .ticket-row { padding: 7px 18px; }
.app-shell.density-compact .local-avatar { width: 30px; height: 30px; font-size: var(--text-xs); }

/* ── Skeleton rows ── */
.skel-row {
  display: grid;
  grid-template-columns: 32px 46px minmax(0, 1fr) 100px 86px 108px 82px 82px 110px 40px;
  gap: 8px;
  align-items: center;
  padding: 12px 18px;
  border-bottom: 1px solid var(--color-border-soft);
}
.skel {
  background: linear-gradient(90deg,
    var(--color-surface-muted) 25%,
    rgba(255,255,255,0.10) 50%,
    var(--color-surface-muted) 75%);
  background-size: 200% 100%;
  animation: skelShimmer 1.4s linear infinite;
  border-radius: var(--radius-sm);
  height: 14px;
}
.skel.skel-avatar { height: 36px; width: 36px; border-radius: 10px; }
.skel.skel-id { height: 12px; width: 40px; }
.skel.skel-line { height: 14px; }
.skel.skel-line-sm { height: 11px; width: 70%; margin-top: 4px; }
@keyframes skelShimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ── Kanban view ── */
.kanban-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 14px;
}
.kanban-col {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  padding: 12px;
  box-shadow: var(--shadow-1);
  display: flex; flex-direction: column; gap: 8px;
  min-height: 200px;
}
.kanban-col-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 4px 6px 8px;
  border-bottom: 1px solid var(--color-border);
  margin-bottom: 4px;
  font-weight: var(--weight-semibold);
  color: var(--color-fg);
  font-size: var(--text-base);
}
.kanban-col-head .count {
  background: var(--color-surface-muted);
  color: var(--color-fg-tertiary);
  border-radius: var(--radius-pill);
  padding: 1px 8px;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
}
.kanban-card {
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  display: flex; flex-direction: column; gap: 6px;
  text-decoration: none;
  color: inherit;
  transition: all var(--duration-fast);
  position: relative;
  border-left: 4px solid var(--borde);
}
.kanban-card:hover { transform: translateY(-1px); box-shadow: var(--shadow-2); border-color: var(--color-accent); }
.kanban-card.is-urgent { border-left-color: var(--color-danger); }
.kanban-card.is-breach { border-left-color: var(--color-danger); }
.kanban-card.is-warn { border-left-color: var(--sla-warn); }
.kanban-card.is-new { border-left-color: var(--color-accent); }
.kanban-card .kc-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 6px;
  font-size: var(--text-xs);
  color: var(--color-fg-tertiary);
}
.kanban-card .kc-id {
  font-family: var(--font-mono);
  font-weight: var(--weight-semibold);
  color: var(--color-fg-secondary);
}
/* El local, escrito, pegado al número: el avatar de dos letras que hay abajo
   no dice de qué local es la incidencia. El `auto` deja la pill del SLA
   pegada a la derecha, que es donde estaba. */
.kanban-card .kc-local {
  color: var(--color-fg);
  font-weight: var(--weight-semibold);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  min-width: 0;
  margin-right: auto;
}
.kanban-card .kc-local::before { content: '·'; color: var(--color-fg-muted); margin-right: 5px; }
.kanban-card .kc-subj {
  font-weight: var(--weight-semibold);
  color: var(--color-fg);
  font-size: var(--text-base);
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.kanban-card .kc-meta {
  display: flex; gap: 6px; align-items: center; flex-wrap: wrap;
  font-size: var(--text-xs);
  color: var(--color-fg-tertiary);
}

/* ── La tarjeta de la cola en el móvil ──

   La fila de escritorio son nueve columnas. En un iPhone sobrevivían tres
   —`36px 1fr auto`— y la primera, de 36 píxeles, le tocaba al ASUNTO: por eso
   la tarjeta salía con el avatar, un icono, un slug y «pending», y sin número,
   sin local, sin asunto y sin saber si alguien había respondido
   (iPhone de Victor, 2026-09-19).

   Ahora en el móvil solo queda UN hijo visible —`.col-subject`— y dentro va la
   tarjeta entera: cabecera (#id · local · estado), asunto, categoría y canal, y
   el pie con el SLA. Lo que en escritorio son columnas propias se marca
   `.solo-movil` y allí no se pinta. */
.solo-movil { display: none; }

@media (max-width: 768px) {
  .inbox-thead { display: none; }
  .ticket-row {
    grid-template-columns: 1fr;
    gap: 10px;
    padding: 14px 14px;
    min-height: 64px;
  }
  .ticket-row .col-checkbox,
  .ticket-row .col-id,
  .ticket-row .col-local,
  .ticket-row .col-dept,
  .ticket-row .col-cat,
  .ticket-row .col-time,
  .ticket-row .col-sla,
  .ticket-row .col-channel,
  .ticket-row .row-actions { display: none; }
  .ticket-row .col-subject { align-items: flex-start; }
  .ticket-row .row-subject { gap: 5px; flex: 1; }
  .ticket-row .solo-movil { display: flex; }
  .ticket-row .row-subject .meta .pieza.solo-movil { display: inline-flex; }

  .ticket-row .card-cabecera {
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    min-width: 0;
  }
  .ticket-row .card-id {
    font-family: var(--font-mono);
    font-weight: var(--weight-semibold);
    color: var(--color-fg-secondary);
  }
  /* El nombre del local, ESCRITO. Las dos letras del avatar no son un nombre:
     «GV» puede ser Gran Vía o cualquier otra cosa. */
  .ticket-row .card-local {
    color: var(--color-fg);
    font-weight: var(--weight-semibold);
    font-size: var(--text-sm);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    min-width: 0;
  }
  .ticket-row .card-cabecera .card-local::before {
    content: '·';
    color: var(--color-fg-muted);
    margin-right: 6px;
  }
  .ticket-row .card-cabecera .badge { margin-left: auto; }

  /* El asunto es lo que de verdad se lee. Dos líneas: una corta de más y tres
     convierten la cola en un muro de texto. */
  .ticket-row .row-subject .subj {
    -webkit-line-clamp: 2;
    white-space: normal;
    font-size: var(--text-base);
    line-height: 1.35;
  }
  .ticket-row .row-subject .meta {
    display: flex; flex-wrap: wrap; gap: 6px;
    margin-top: 0;
    font-size: var(--text-xs);
  }

  /* El pie: cuánto queda (o cuánto se pasó), cuándo se movió por última vez y
     si nadie ha contestado todavía. */
  .ticket-row .card-sla {
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    font-size: var(--text-xs);
  }
  .ticket-row .card-sla .card-cuando { color: var(--color-fg-tertiary); }

  .skel-row {
    grid-template-columns: 36px 1fr 60px;
  }
  .skel-row .skel-only-desktop { display: none; }
}

/* ── La cola en ESCRITORIO: lo que el móvil no necesita ──

   A partir de 769 px la fila vuelve a ser una fila de tabla, y eso cambia dos
   cosas respecto a la tarjeta del teléfono. Va en su propia consulta —y no
   suelto— para que no haya ninguna duda de que el móvil, que costó dos
   vueltas y Victor ya dio por bueno, no se toca. */
@media (min-width: 769px) {
  /* La categoría se esconde de la tira de debajo del asunto porque tiene
     columna propia. Se escribe con los tres selectores y no confiando en
     `.solo-movil` a secas: `.row-subject .meta .pieza` ya vale 0-3-0 y le gana
     a una clase suelta, así que el `display: none` global no la escondía y la
     categoría seguía saliendo dos veces (medido el 2026-09-21). */
  .row-subject .meta .pieza.solo-movil { display: none; }
  /* El «·» lo pinta el hermano SIGUIENTE (`.pieza + .pieza::before`), así que
     al esconder la categoría quedaba un punto huérfano abriendo la tira. */
  .row-subject .meta .pieza.solo-movil + .pieza::before { content: none; }
}

/* ── Escritorio estrecho (el portátil de 1280) ──

   Con la barra lateral y los márgenes, a 1280 la fila tiene 916 px útiles: es
   el ancho donde se vio el defecto. Aquí las columnas tasadas se aprietan un
   poco más —y las pastillas de plazo pierden relleno, no texto— para que el
   asunto siga teniendo sitio. Nada se esconde: cada dato sigue apareciendo una
   vez y en su columna. */
@media (min-width: 769px) and (max-width: 1339px) {
  .inbox-thead,
  .ticket-row,
  .skel-row {
    grid-template-columns: 28px 42px minmax(0, 1fr) 82px 74px 90px 82px 82px 96px 40px;
    gap: 6px;
  }
  .ticket-row .sla-pill { padding: 3px 6px; gap: 4px; }
  .inbox-thead { font-size: 12px; }
}

/* ── Conversación tipo chat ── */
.thread { display: flex; flex-direction: column; gap: 14px; padding: 8px 0; }
.msg {
  display: flex; gap: 10px;
  max-width: 80%;
}
.msg.from-customer  { align-self: flex-start; }
.msg.from-agent     { align-self: flex-end;   flex-direction: row-reverse; }
.msg .avatar {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: var(--color-fg-tertiary);
  color: var(--color-fg-inverse);
  display:flex; align-items:center; justify-content:center;
  font-size: var(--text-sm); font-weight: var(--weight-bold);
  flex-shrink: 0;
}
.msg.from-agent .avatar { background: var(--color-accent); }
.msg.internal .avatar { background: var(--color-warning); }
.msg .bubble {
  background: var(--color-surface-muted);
  border-radius: var(--radius-lg);
  padding: 10px 14px;
  font-size: 14px;
  line-height: 1.45;
  white-space: pre-wrap;
  word-wrap: break-word;
  color: var(--color-fg);
  border: 1px solid var(--color-border);
}
.msg.from-agent .bubble {
  background: var(--brand-100);
  color: var(--color-info-fg);
  border-color: rgb(var(--sombra-tinta) / 0.2);
}
/* En noche, esta regla ponía `color` y `background` al MISMO token
   (`--color-accent-soft`): texto gris sobre gris, la burbuja del técnico
   ilegible en el iPhone. El texto de una burbuja es texto y va con el color de
   texto; el acento se queda donde se ve, en el fondo y en el borde. */
html[data-theme="dark"] .msg.from-agent .bubble {
  background: var(--color-accent-soft);
  color: var(--color-fg);
  border-color: var(--color-accent);
}
/* La nota interna en noche: el fondo es un rgba fijo (no un token), así que
   sobre la pizarra queda casi negro y el ámbar de día no se lee encima. */
html[data-theme="dark"] .msg.internal .bubble {
  background: rgb(227 166 63 / 0.12);
  color: var(--color-fg);
  border-color: var(--color-warning);
}
.msg.internal .bubble {
  background: rgb(168 113 26 / 0.14);
  color: var(--color-warning-fg);
  border: 1px solid var(--color-warning);
}
.msg .meta-author {
  font-size: var(--text-xs); font-weight: var(--weight-semibold); color: var(--color-fg);
  margin-bottom: 3px;
}
.msg .meta-time { font-size: 12px; color: var(--color-fg-muted); margin-top: 4px; }

.attachments { margin-top: 8px; display: flex; flex-direction: column; gap: 6px; }
.attachments img { max-width: 280px; max-height: 280px; border-radius: var(--radius-md); }
.attachments audio { width: 100%; max-width: 320px; }
.attachments .att-file {
  font-size: var(--text-sm); color: var(--color-accent);
  display: inline-flex; align-items: center; gap: 6px;
  text-decoration: none;
}

/* ── Reply form ── */
.reply-form {
  background: var(--color-surface-strong);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  padding: 14px;
  margin-top: 18px;
  position: sticky; bottom: 14px;
  box-shadow: var(--shadow-2);
}
.reply-form .scope-toggle {
  display: flex; gap: 8px;
  margin-bottom: 8px;
}
.reply-form .scope-toggle label {
  flex: 1;
  padding: 6px 10px;
  border-radius: var(--radius-md);
  text-align: center;
  font-size: var(--text-sm);
  cursor: pointer;
  border: 1px solid var(--color-border-strong);
  font-weight: var(--weight-medium);
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  color: var(--color-fg-secondary);
  transition: all var(--duration-fast);
}
.reply-form .scope-toggle input { display: none; }
.reply-form .scope-toggle input:checked + label.public  {
  background: var(--brand-100); color: var(--brand-800); border-color: var(--brand-500);
}
html[data-theme="dark"] .reply-form .scope-toggle input:checked + label.public {
  background: var(--color-accent-soft); color: var(--color-accent); border-color: var(--color-accent);
}
.reply-form .scope-toggle input:checked + label.internal {
  background: rgb(168 113 26 / 0.16); color: var(--color-warning-fg); border-color: var(--color-warning);
}
.reply-form textarea {
  width: 100%;
  padding: 10px;
  font-family: inherit;
  font-size: 14px;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  resize: vertical;
  min-height: 90px;
  background: var(--color-bg-elevated);
  color: var(--color-fg);
}
.reply-form textarea:focus {
  outline: none;
  border-color: var(--color-accent);
  box-shadow: 0 0 0 3px var(--color-accent-soft);
}
.reply-form .toolbar {
  display: flex; gap: 8px; align-items: center;
  margin-top: 10px;
  flex-wrap: wrap;
}
/* Adjuntar a la respuesta: el `input` escondido y su etiqueta, que es un `.btn`
   de los de siempre y por tanto mide 44. El alto lo ponía antes el control
   nativo del navegador —20 px— y no hay CSS que lo suba. */
.reply-attach {
  display: flex; align-items: center; gap: 8px;
  margin-top: 6px;
}
/* El nombre del fichero elegido se escribe dentro del botón: si es largo se
   corta con puntos suspensivos en vez de empujar la ficha a lo ancho. */
.reply-attach .btn { max-width: 100%; min-width: 0; }
.reply-attach .btn span { overflow: hidden; text-overflow: ellipsis; min-width: 0; }

.reply-form .char-count {
  font-size: var(--text-xs);
  color: var(--color-fg-muted);
  font-variant-numeric: tabular-nums;
}

.template-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 10px;
  background: var(--color-surface-muted);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  cursor: pointer;
  user-select: none;
  border: 1px solid transparent;
  color: var(--color-fg-secondary);
  transition: all var(--duration-fast);
}
.template-chip:hover { background: var(--color-accent-soft); border-color: var(--color-accent); color: var(--color-accent); }
.template-chip.is-internal { background: rgb(168 113 26 / 0.12); color: var(--color-warning-fg); }
.template-chip.is-internal:hover { border-color: var(--color-warning); }

.tpl-search {
  width: 100%;
  padding: 5px 10px 5px 28px;
  font-size: var(--text-sm);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-bg-elevated);
  color: var(--color-fg);
  position: relative;
}
.tpl-search-wrap { position: relative; margin-bottom: 6px; }
.tpl-search-wrap .icon-search {
  position: absolute; left: 8px; top: 50%; transform: translateY(-50%);
  width: 14px; height: 14px; color: var(--color-fg-muted);
}

/* ── Ticket detail layout ── */
.ticket-meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px 18px;
  font-size: var(--text-sm);
}
.ticket-meta .meta-cell .label {
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--color-fg-muted);
  font-weight: var(--weight-semibold);
}
.ticket-meta .meta-cell .val {
  font-weight: var(--weight-medium);
  color: var(--color-fg);
}

/* `minmax(0, 1fr)` y no `1fr`, que es `minmax(auto, 1fr)`: con `auto` la
   columna no baja del contenido más ancho que no se puede partir, y una fila
   así ensanchaba la rejilla entera. Victor, 2026-10-10, en su iPhone: todas
   las tarjetas de la ficha cortadas por la derecha y el hueco del margen a la
   izquierda; la culpable era la lista «Otros tickets» (ver `.subj`), que a
   390 empujaba la columna a 493 px. */
.ticket-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 16px;
  height: calc(100dvh - 200px);
  min-height: 540px;
}
.ticket-main {
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  overflow: hidden;
  box-shadow: var(--shadow-1);
}
.ticket-main-header {
  padding: 14px 20px;
  border-bottom: 1px solid var(--color-border);
  flex-shrink: 0;
}
.thread-scroll {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 18px 20px;
  min-height: 0;
}
.ticket-main .reply-form {
  position: relative;
  bottom: auto;
  margin: 0;
  border-top: 1px solid var(--color-border);
  border-radius: 0;
  border-left: 0; border-right: 0; border-bottom: 0;
  box-shadow: none;
  flex-shrink: 0;
}
.ticket-side {
  display: flex;
  flex-direction: column;
  gap: 12px;
  overflow-y: auto;
  min-height: 0;
}

@media (max-width: 900px) {
  .ticket-layout {
    grid-template-columns: minmax(0, 1fr);
    height: auto;
  }
  .ticket-side { overflow: visible; }
}

/* Ticket header SLA strip */
.ticket-summary {
  display: flex; gap: 16px; align-items: center;
  padding: 10px 14px;
  background: var(--color-surface-muted);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  margin-bottom: 14px;
  flex-wrap: wrap;
  font-size: var(--text-sm);
}
.ticket-summary .sum-cell {
  display: flex; flex-direction: column;
}
.ticket-summary .sum-label {
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--color-fg-muted);
  font-weight: var(--weight-semibold);
}
.ticket-summary .sum-value {
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  color: var(--color-fg);
}
.ticket-summary .sum-value.is-warn { color: var(--sla-warn); }
.ticket-summary .sum-value.is-breach { color: var(--color-danger); }
.ticket-summary .sum-spacer { flex: 1; }
.ticket-summary .sum-summary {
  flex-basis: 100%;
  font-size: var(--text-sm);
  color: var(--color-fg-secondary);
  border-top: 1px solid var(--color-border-soft);
  padding-top: 8px;
  margin-top: 2px;
  display: flex; gap: 6px; align-items: flex-start;
}
.ticket-summary .sum-summary .icon { color: var(--color-accent); width: 14px; height: 14px; flex-shrink: 0; margin-top: 2px; }
/* «Llegó hace 10 min · reclasificada desde IT».
 *
 * Va con el color de aviso y no con el de peligro: no es que algo esté mal, es
 * que la antigüedad de al lado no cuenta lo que parece. Quien la recibe tiene
 * que poder leer las dos cosas de una vez. */
.ticket-summary .sum-reclasificada { color: var(--color-fg); }
.ticket-summary .sum-reclasificada .icon { color: var(--sla-warn); }

/* ── El bloque «Detalles», cuando se puede editar ──
 *
 * Seis desplegables en una columna estrecha: la separación la pone el `gap` y
 * no un margen por campo, para que el último no arrastre un hueco muerto antes
 * del botón. Los controles ya miden 44 px por `.field-select`. */
.cls-form { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.cls-form .field-select { max-width: 100%; }
.cls-guardar { width: 100%; justify-content: center; margin-top: 2px; }
/* La nota de la sección: por qué es obligatoria en cuanto la rama la tiene.
 * Va debajo del control y no en el `label` para no partir la etiqueta en dos
 * líneas en el móvil, que es donde se clasifica. */
.cls-form .field-nota {
  margin: 4px 0 0;
  font-size: var(--text-xs);
  color: var(--color-fg-muted);
}
/* `[hidden]` no sobrevive a un `display` propio; aquí no lo hay, pero se deja
 * escrito por lo de siempre (ver `.cls-aviso[hidden]`). */
.cls-form .field-nota[hidden] { display: none; }
.cls-aviso {
  display: flex; gap: 6px; align-items: flex-start;
  margin: 0;
  font-size: var(--text-xs);
  color: var(--color-fg);
  background: var(--color-surface-muted);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 8px 10px;
}
.cls-aviso .icon { width: 14px; height: 14px; flex-shrink: 0; margin-top: 1px; color: var(--sla-warn); }
/* `display: flex` gana a `[hidden]`, que solo vale `display: none` de agente de
 * usuario: sin esto el aviso salía como una caja vacía con una flechita y sin
 * texto, que es exactamente lo que parece un fallo de la pantalla. */
.cls-aviso[hidden] { display: none; }

/* La marca de la tarjeta de la cola: «desde IT». Es una pastilla más de las
 * que ya lleva la fila (urgente, sin responder, perseguir), no una fila nueva:
 * la tarjeta no puede crecer por esto. */
.badge.badge-reclasificada {
  background: var(--color-surface-muted);
  color: var(--sla-warn);
  border: 1px solid var(--sla-warn);
}

/* «Sin tipificar»: la incidencia entró sin avería y está en el departamento de
 * entrada esperando a que alguien la clasifique. Es trabajo pendiente, no una
 * alarma —la alarma la da el SLA—, así que van los tokens de AVISO y no los de
 * peligro; son los mismos que ya usa `badge-handoff`, y por tanto se leen igual
 * de bien en claro y en oscuro sin añadir ningún color nuevo. */
.badge.badge-sin-tipificar {
  background: var(--color-warning-soft);
  color: var(--color-warning-fg);
}

/* Ticket sidebar collapsible sections */
.side-section {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  padding: 14px 16px;
  box-shadow: var(--shadow-1);
}
.side-section summary {
  display: flex; align-items: center; gap: 8px;
  font-weight: var(--weight-semibold);
  font-size: var(--text-base);
  color: var(--color-fg);
  cursor: pointer;
  list-style: none;
}
.side-section summary::-webkit-details-marker { display: none; }
.side-section summary .icon { width: 16px; height: 16px; color: var(--color-fg-tertiary); }
.side-section summary::after {
  content: '+';
  margin-left: auto;
  font-weight: var(--weight-semibold);
  color: var(--color-fg-muted);
  font-size: var(--text-md);
}
.side-section[open] summary::after { content: '−'; }
/* Un correo o un enlace largo en el lateral se parte en vez de salirse. */
.side-section .side-body { margin-top: 10px; overflow-wrap: anywhere; }

/* ── El pedido de la incidencia (Compras) ──
   Lo que se lee de un vistazo es a quién se le reclama. El aviso ámbar es el
   caso de «la dirección de pedido es NUESTRA»: uno de cada diez pedidos de BC
   resuelve a `@gruposaona.com` y mandar la reclamación ahí es mandársela a la
   casa, así que se ve, no se disimula. `word-break` porque un correo largo en
   una columna de 320 px desborda el lateral. */
.pedido-correo,
.pedido-aviso {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin: 10px 0 0;
  font-size: var(--text-xs);
  line-height: 1.45;
  word-break: break-word;
}
.pedido-correo { color: var(--color-fg-secondary); }
.pedido-correo .icon,
.pedido-aviso .icon { width: 14px; height: 14px; flex: 0 0 auto; margin-top: 1px; }
.pedido-aviso-nuestro {
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: var(--color-warning-soft);
  color: var(--color-warning-fg);
}

/* Status quick switch */
.status-quick {
  display: flex; flex-direction: column; gap: 6px;
}
.status-quick button {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px;
  /* «Reabrir» y «Resolver» no llevan `.btn` —son la caja de estado del lateral,
     con su punto de color— y medían 32 px de alto. Son las dos acciones que
     cambian el estado de la incidencia: si el dedo falla aquí, se reabre lo que
     se quería resolver. */
  min-height: var(--toque-min);
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  background: var(--color-bg-elevated);
  cursor: pointer;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--color-fg-secondary);
  font-family: inherit;
  transition: all var(--duration-fast);
}
.status-quick button:hover:not(:disabled) {
  border-color: var(--color-accent);
  background: var(--color-accent-softer);
  color: var(--color-accent);
}
.status-quick button:disabled { opacity: 0.55; cursor: not-allowed; }
.status-quick .dot {
  width: 8px; height: 8px; border-radius: 50%;
}

/* Local tickets list (sidebar) */
.local-tickets-list {
  display: flex; flex-direction: column; gap: 4px;
  max-height: 200px; overflow-y: auto;
}
.local-ticket-item {
  display: flex; gap: 8px; align-items: center;
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: inherit;
  font-size: var(--text-sm);
  transition: background var(--duration-fast);
}
/* 44 px de alto mínimo: medido a 390 px el 2026-10-02, estas filas salían a
   328x26 y son enlaces que se pulsan con el dedo en la barra de un local. Es la
   única zona de toque pequeña que quedaba en las pantallas de incidencias. */
.local-ticket-item { min-height: 44px; }
.local-ticket-item:hover { background: var(--color-accent-softer); }
.local-ticket-item .id {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-fg-tertiary);
  flex-shrink: 0;
}
/* `min-width: 0`: un hijo de flex no encoge por debajo de su contenido, y con
   `nowrap` su contenido es el asunto ENTERO. Sin esto la elipsis no salía
   nunca y el asunto más largo del local ensanchaba la ficha (2026-10-10). */
.local-ticket-item .subj {
  flex: 1;
  min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--color-fg);
}

/* ── Tareas en otros departamentos (2026-10-06) ──
 * Una fila por tarea: departamento y estado en la cabeza, lo que se pidió
 * debajo y en dos líneas como mucho. La fila entera es el enlace (≥ 44 px)
 * cuando quien mira puede abrir la hija; si no, la misma fila sin enlace. */
.tareas-lista { list-style: none; margin: 0 0 10px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.tarea-enlace {
  display: flex; flex-direction: column; gap: 3px;
  min-height: 44px; padding: 8px 10px;
  border: 1px solid var(--color-border-soft); border-radius: var(--radius-md);
  color: inherit; text-decoration: none;
}
a.tarea-enlace:hover { background: var(--color-accent-softer); }
.tarea-cabeza { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: var(--text-sm); }
.tarea-cabeza .id { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-fg-tertiary); }
.tarea-cabeza .badge { margin-left: auto; }
.tarea-que {
  font-size: var(--text-sm); color: var(--color-fg-secondary);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  overflow-wrap: anywhere;
}
/* El título (2026-10-07) es lo que se reconoce de un vistazo; lo pedido queda
   debajo como detalle. */
.tarea-titulo { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-fg); overflow-wrap: anywhere; }
.tarea-fila.is-terminada .tarea-que,
.tarea-fila.is-terminada .tarea-titulo { color: var(--color-fg-tertiary); }
.tarea-vacia { margin: 0 0 10px; font-size: var(--text-sm); color: var(--color-fg-secondary); }
.tarea-pedir { width: 100%; min-height: 44px; justify-content: center; }
/* En la caja de respuesta de una tarea, en lugar del «Pública / Nota interna». */
.tarea-solo-notas {
  display: flex; gap: 6px; align-items: flex-start; margin: 0 0 8px;
  font-size: var(--text-sm); color: var(--color-fg-secondary);
}
.tarea-solo-notas .icon { width: 14px; height: 14px; flex-shrink: 0; margin-top: 2px; }
/* Plantilla que no casa con el modo (plantilla-modo.js): el modo NO ha
   cambiado y hay que decirlo junto a la caja. */
.aviso-plantilla {
  margin: 6px 0 0;
  font-size: var(--text-xs); font-weight: 500;
  color: var(--color-warning-fg, var(--color-warning));
}
.aviso-plantilla[hidden] { display: none; }
.ticket-summary .sum-tarea { color: var(--color-fg); }
.ticket-summary .sum-tarea a { color: var(--color-accent); font-weight: var(--weight-semibold); }

/* ── Filter checkboxes (admin + filtros modal) ── */
.filter-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
  margin-top: 12px;
}
.filter-group {
  background: var(--color-surface-muted);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: 12px;
}
.filter-group legend, .filter-group .legend {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--color-fg-secondary);
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.filter-group .legend .icon { width: 13px; height: 13px; color: var(--color-fg-tertiary); }
.filter-group .check-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  /* Las listas crecen con las filas: con 44 px por casilla y el alto de antes
     se veían cuatro opciones de doce y parecía que no había más. */
  max-height: 264px;
  overflow-y: auto;
  padding-right: 4px;
}
.filter-group.scrollable .check-list { max-height: 308px; }
.check-item {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 14px;
  cursor: pointer;
  user-select: none;
  /* La etiqueta ENTERA es el área tocable de la casilla: pulsar un `label`
     marca su `input`, así que el mínimo va aquí y no en el cuadradito. */
  min-height: var(--toque-min);
  padding: 6px 8px;
  border-radius: var(--radius-xs);
  transition: background var(--duration-fast);
  color: var(--color-fg-secondary);
}
.check-item:hover { background: var(--color-accent-softer); color: var(--color-fg); }
.check-item input { cursor: pointer; }
.check-item.disabled { color: var(--color-fg-muted); }

.filter-search {
  width: 100%;
  padding: 5px 8px;
  margin-bottom: 6px;
  font-size: var(--text-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg-elevated);
  color: var(--color-fg);
}
.filter-search:focus { outline: none; border-color: var(--color-accent); }

.filter-help {
  margin-top: 6px;
  font-size: var(--text-xs);
  color: var(--color-fg-muted);
  font-style: italic;
}

/* ── Modal ── */
.saona-modal-backdrop {
  position: fixed; inset: 0;
  background: rgb(var(--sombra-tinta) / 0.55);
  z-index: var(--z-modal);
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  animation: fadeBg 200ms var(--ease-out);
}
@keyframes fadeBg {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.saona-modal {
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-2xl);
  padding: 22px 24px;
  width: 100%;
  max-width: 720px;
  max-height: 88vh;
  overflow-y: auto;
  box-shadow: var(--shadow-3);
  animation: modalIn 250ms var(--ease-spring);
}
@keyframes modalIn {
  from { opacity: 0; transform: translateY(20px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.saona-modal-head {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 12px;
}
.saona-modal-head h2 {
  font-size: var(--text-xl);
  font-weight: var(--weight-bold);
  margin: 0;
  color: var(--color-fg);
}
.saona-modal-head .close-btn {
  margin-left: auto;
  background: transparent; border: 0;
  width: 32px; height: 32px;
  border-radius: var(--radius-sm);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  color: var(--color-fg-tertiary);
  font-size: 22px; line-height: 1;
}
.saona-modal-head .close-btn:hover { background: var(--color-surface-muted); color: var(--color-fg); }

/* ── Mobile / Responsive ── */
.mobile-topbar { display: none; }
.sidebar-backdrop { display: none; }

@media (max-width: 768px) {
  .app-shell { display: block; }

  .mobile-topbar {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    padding-top: max(10px, env(safe-area-inset-top));
    background: var(--color-surface-strong);
    border-bottom: 1px solid var(--color-border);
    position: sticky;
    top: 0;
    z-index: var(--z-mobile-bar);
  }
  .topbar-burger, .topbar-notif {
    background: var(--color-accent-softer);
    border: none;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-md);
    display: flex; align-items: center; justify-content: center;
    color: var(--color-accent);
    cursor: pointer;
  }
  .topbar-burger:active, .topbar-notif:active { background: var(--color-accent-soft); }
  .topbar-burger .icon, .topbar-notif .icon { width: 22px; height: 22px; }
  .topbar-title {
    flex: 1;
    display: flex; align-items: center; gap: 8px;
    font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); color: var(--color-fg);
  }
  .topbar-title .logo-mark.sm {
    width: 28px; height: 28px;
    border-radius: var(--radius-md);
    background: var(--color-accent);
    color: var(--color-accent-fg);
    display: flex; align-items: center; justify-content: center;
    font-size: 14px; font-weight: var(--weight-bold);
  }

  .app-sidebar {
    position: fixed;
    top: 0; left: 0; bottom: 0;
    width: 280px;
    transform: translateX(-100%);
    transition: transform 250ms var(--ease-out);
    border-radius: 0 var(--radius-xl) var(--radius-xl) 0;
    z-index: var(--z-sidebar);
    box-shadow: 8px 0 32px rgb(var(--sombra-tinta) / 0.18);
  }
  body.sidebar-open .app-sidebar { transform: translateX(0); }

  .sidebar-backdrop {
    display: block;
    position: fixed; inset: 0;
    background: rgb(var(--sombra-tinta) / 0.4);
    opacity: 0;
    pointer-events: none;
    transition: opacity 250ms;
    z-index: var(--z-backdrop);
  }
  body.sidebar-open .sidebar-backdrop {
    opacity: 1;
    pointer-events: auto;
  }

  .app-main {
    padding: 14px 12px 32px;
    padding-bottom: max(32px, env(safe-area-inset-bottom));
  }

  .page-header { margin-bottom: 14px; }
  .page-title { font-size: 24px; line-height: 30px; }
  .page-subtitle { font-size: var(--text-sm); }

  .ticket-main .reply-form {
    padding: 12px;
    padding-bottom: max(12px, env(safe-area-inset-bottom));
  }
  .reply-form textarea { font-size: 16px; }

  .ticket-layout {
    height: auto;
    min-height: 0;
  }
  .thread-scroll { overflow-y: visible; padding: 14px; }
  .ticket-main { border-radius: var(--radius-lg); }

  .filter-grid { grid-template-columns: 1fr; }
  input, select, textarea { font-size: 16px; }

  .inbox-toolbar { flex-direction: column; align-items: stretch; }
  .inbox-search { max-width: none; }
}

/* ── Banner tickets nuevos ── */
.new-tickets-banner {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  background: var(--color-accent-soft);
  border: 1px solid rgb(var(--sombra-tinta) / 0.30);
  color: var(--color-accent);
  border-radius: var(--radius-lg);
  font-size: var(--text-base); font-weight: var(--weight-medium);
  margin-bottom: 14px;
  animation: bannerIn 280ms var(--ease-out);
}
.new-tickets-banner[hidden] { display: none; }
.new-tickets-banner .banner-action {
  margin-left: auto;
  background: var(--color-accent);
  color: var(--color-accent-fg);
  padding: 5px 12px;
  border-radius: var(--radius-sm);
  text-decoration: none;
  font-size: var(--text-sm); font-weight: var(--weight-semibold);
}
.new-tickets-banner .banner-action:hover { background: var(--color-accent-hover); }
.new-tickets-banner .banner-close {
  background: transparent;
  border: none;
  color: var(--color-fg-tertiary);
  font-size: 18px; line-height: 1;
  cursor: pointer;
  padding: 2px 8px;
}
.new-tickets-banner .banner-close:hover { color: var(--color-danger); }

@keyframes bannerIn {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ── Empty state ── */
.empty-state {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 48px 24px;
  gap: 8px;
  text-align: center;
}
.empty-state .icon-large { width: 36px; height: 36px; color: var(--color-fg-muted); }
.empty-state .empty-state-title {
  font-size: var(--text-md); font-weight: var(--weight-semibold);
  color: var(--color-fg);
  margin-top: 4px;
}
.empty-state .empty-state-msg {
  font-size: var(--text-sm); color: var(--color-fg-tertiary);
  max-width: 380px;
}

/* ── Spin animation utility ── */
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes pulse {
  0% { box-shadow: 0 0 0 0 rgb(47 107 86 / 0.6); }
  70% { box-shadow: 0 0 0 8px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

/* ── Refresh button spin on click ── */
.btn.is-spinning .icon {
  animation: spin 700ms linear;
}

/* (Aquí hubo un titular con degradado recortado al texto. Al quitar el
   degradado quedó el relleno transparente sin fondo: los titulares de
   toda pantalla con .page-header eran invisibles, de día y de noche, desde
   de90427. Detectado en capturas el 2026-09-19.) */

/* ── Inbox controls grouping ── */
.inbox-controls {
  position: relative;
  padding: 12px 14px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-1);
}
.inbox-controls::after {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 0 0 1px rgba(255, 255, 255, 0.18);
}
html[data-theme="dark"] .inbox-controls::after {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    inset 0 0 0 1px rgba(255, 255, 255, 0.04);
}
.inbox-controls > * { position: relative; z-index: 1; }

/* ═══ LA COLA EN UN TELÉFONO ═══════════════════════════════════════════════
 *
 * En el iPhone de Victor (390x844, de noche) la primera tarjeta empezaba en
 * y=604: el 71% de la pantalla era cabecera y mandos, y la cola —que es a lo
 * que se entra— quedaba debajo del pliegue. Se llegaba ahí por acumulación:
 * subtítulo de atajos, hora del último refresco, siete píldoras que envuelven
 * en cuatro filas, buscador, dos conmutadores de vista y dos botones.
 *
 * El arreglo NO duplica el HTML ni esconde nada del JS: todo sigue en el DOM
 * —así `inbox.js` no tiene que preguntar si un control existe— y lo único que
 * cambia es dónde se pinta. Los envoltorios (`.metrics-estado`,
 * `.metrics-accion`) son `display: contents` en el ordenador: no crean caja,
 * así que la fila de mandos de escritorio es exactamente la de antes.
 *
 * En el móvil, `.inbox-metrics` pasa a `display: contents` y entonces todo
 * —resumen, píldoras y barra de herramientas— son hermanos de la misma columna
 * y se ordenan con `order`.
 *
 * Las cuatro píldoras de las marcas filtran desde el 2026-10-10, de una en
 * una (el porqué, en `inbox.html`). Quién tiene la pelota lo sigue decidiendo
 * el reparto de la lista: el contador recorta los grupos, no los sustituye. */
.metrics-estado,
.metrics-accion { display: contents; }
.inbox-resumen,
.cabecera-recargar,
.titulo-cuenta { display: none; }
.cabecera-nueva { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; }

@media (max-width: 768px) {
  /* ── 1. La cabecera, una línea ──────────────────────────────────────────
     «Mis tickets · N ●» y el icono de recargar a la derecha. El subtítulo de
     los atajos no pinta nada donde no hay teclado, y la hora del último
     refresco tampoco: el punto verde ya dice que está vivo. */
  .cola-cabecera {
    flex-wrap: nowrap;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
  }
  .cola-cabecera .cola-titulo { flex: 0 1 auto; min-width: 0; }
  .cola-cabecera .page-title {
    font-size: 19px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    /* Sin el troquel de puntos: es la firma de la casa bajo cada titular, pero
       aquí son 20px (6 de puntos y 14 de aire) para pintar un adorno encima de
       la cola, y encima queda huérfano al lado de una sola línea. En el
       ordenador sigue donde siempre. */
    padding-bottom: 0;
  }
  .cola-cabecera .page-title::after { display: none; }
  .cola-cabecera .page-subtitle { display: none; }
  .cola-cabecera .titulo-cuenta { display: inline; }
  .cola-cabecera .live-indicator { flex: none; }
  .cola-cabecera .live-texto { display: none; }
  .cola-cabecera .cabecera-recargar {
    display: inline-flex;
    flex: none;
    margin-left: auto;
    padding: 7px 9px;
  }
  /* «Nueva incidencia» (admin): el mismo cuadrado de 44 que recargar. */
  .cola-cabecera .cabecera-nueva {
    flex: none; min-width: 44px; min-height: 44px; padding: 0;
    justify-content: center;
  }
  .cola-cabecera .cabecera-nueva-texto { display: none; }

  /* ── 2. Los mandos, una columna sin envoltorios ─────────────────────── */
  .inbox-controls { padding: 10px; gap: 7px; margin-bottom: 8px; }
  .inbox-metrics { display: contents; }
  /* El brillo interior de `.inbox-controls::after` se pinta encima: los hijos
     que ahora suben un nivel necesitan su propia capa, como los de antes. */
  .inbox-metrics > * { position: relative; z-index: 1; }

  /* El desglose de estado: tres píldoras que no filtran valían una fila
     entera. Fueron una línea de texto («3 tickets · 1 pendiente de ti…»)
     hasta el 2026-10-10: desde la cola nueva (#90) lo dicen ya el selector de
     estado y los títulos de grupo, y Victor la quitó del móvil para ganar
     sitio. Sigue oculta como en el escritorio (`.inbox-resumen` arriba). */
  .metrics-estado { display: none; }

  /* ── 3. Los cuatro contadores, en UNA fila de cuatro ───────────────────
     Historia: hasta el 2026-10-10 iban en una fila que se deslizaba de lado
     con la barra escondida, y a 390 «Vencidos» salía cortado sin que nada
     dijera que había más. El #86 los puso en dos filas de dos, todos a la
     vista, pero eran 94 px de botones de 167 de ancho para decir un número;
     con la cola nueva (#90) encima van además el buscador y la pestaña de
     estado, y la primera incidencia se iba a y=420 en el iPhone.

     Ahora son cuatro casillas iguales, el número grande encima y el rótulo
     corto debajo: el mismo ritmo de cuatro que «Por hacer · En espera ·
     Resueltas · Todas», que va justo encima, y los cuatro a la vista sin
     deslizar, que es lo que no se puede perder. Cada una mide 44 de alto (el
     dedo) y unos 75 de ancho a 375. Se distinguen de la pestaña de encima por el
     borde de color y porque no van dentro de un carril: son botones sueltos.

     El rótulo largo no se borra: se aparta de la vista pero se queda para el
     lector de pantalla, que anuncia «SLA en riesgo» y no «En riesgo». */
  .metrics-accion {
    order: 2;
    display: grid;
    /* `1fr` y no `minmax(0, 1fr)`: con `min-width: 0` en cada botón ya no se
       ensanchan por el texto, y `minmax(0, 1fr)` es la firma de las rejillas
       de la lista que cuenta `test_cola_escritorio`. */
    grid-template-columns: repeat(4, 1fr);
    gap: 6px;
    min-width: 0;
  }
  .metrics-accion .metric-pill {
    min-width: 0;
    min-height: var(--toque-min);
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;
    padding: 3px 4px;
    border-radius: var(--radius-md);
    text-align: center;
  }
  .metrics-accion .metric-pill .value {
    order: -1;
    font-size: 17px;
    line-height: 1.1;
  }
  .metrics-accion .metric-pill .label {
    position: absolute;
    width: 1px; height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .metrics-accion .metric-pill .label-corta {
    display: block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 12px;
    line-height: 1.2;
    color: var(--color-fg-tertiary);
  }
  .metrics-accion .metric-pill.is-active .label-corta { color: inherit; }


  /* ── 4. Buscar y Filtros ─────────────────────────────────────────────── */
  /* `order: 1`: la barra —y con ella el selector de estado— va ANTES que los
     contadores (el porqué, en «LA COLA NUEVA», más abajo). */
  .inbox-toolbar { order: 1; gap: 8px; }
  /* El atajo `/` es del teclado: en un teléfono solo ocupa sitio, y sin él el
     campo puede respirar hasta el borde. */
  .inbox-search .atajo-barra { display: none; }
  .inbox-search input { padding-top: 7px; padding-bottom: 7px; }
  /* Lista/tablero y densidad NO se borran del DOM —`inbox.js` sigue
     enganchándolos y leyendo la vista guardada—; simplemente no se pintan:
     en una pantalla de 390px el tablero no cabe y la densidad no se nota. */
  .toolbar-spacer,
  .conmutador-vista,
  #btnRefresh { display: none; }

  /* Aquí estaba «Más filtros»: una casilla que plegaba WhatsApp, Email, Hoy y
     >24h. Se ha ido con los chips (2026-09-20): el canal ya se filtra en el
     modal de «Filtros» —que ahora es el ÚNICO sitio donde se filtra— y la
     antigüedad la resuelve el orden, que pone lo más antiguo arriba dentro de
     cada tramo.

     ── El grupo «Esperando» en un teléfono ──
     La cabecera del grupo es lo único que se toca de esta parte, así que se
     queda con el cuadrado del dedo; la pista de al lado no cabe en 390. */
  .grupo-pista { display: none; }
}

/* ═══ LA COLA REPARTIDA: DE QUIÉN ES LA PELOTA ════════════════════════════
 *
 * «Los filtros de la cola no son lógicos, no consigo ver mis tickets en una
 * misma vista» (Victor, 2026-09-20). TRES grupos en la misma pantalla y en
 * orden fijo: «Pendientes de ti» (lo que hay que resolver), «Perseguir» (lo
 * que espera fuera con el plazo vencido, desplegado) y «Esperando» (lo que
 * espera fuera dentro de plazo, plegado).
 *
 * Solo el tercero se pliega, y el plegado es CSS puro: una casilla
 * (`#verEsperando`) que vive FUERA del fragmento que htmx reemplaza cada 30 s,
 * para que el refresco no cierre el grupo que alguien acaba de abrir. Sin JS,
 * así que tampoco depende de que el script haya cargado. */
.ver-esperando-check {
  /* Escondida pero NO `display: none`: tiene que poder recibir el foco para
     que funcione con teclado y con lector de pantalla. */
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  margin: 0;
}
.grupo-cabecera {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: var(--toque-min);
  padding: 8px 18px;
  border-top: 1px solid var(--color-border);
  background: var(--color-surface-muted);
  color: var(--color-fg-secondary);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  cursor: pointer;
  user-select: none;
}
.grupo-cabecera:hover { color: var(--color-fg); }
/* Los dos primeros grupos no se pliegan: su cabecera es un rótulo y no un
   botón, así que ni cursor de mano ni cambio de color al pasar por encima. Lo
   que no se puede pulsar no debe parecer que se pulsa. */
.grupo-cabecera-fija { cursor: default; }
.grupo-cabecera-fija:hover { color: var(--color-fg-secondary); }
#verEsperando:focus-visible ~ #inboxContainer [data-grupo="esperando"] .grupo-cabecera,
#verResueltas:focus-visible ~ #inboxContainer [data-grupo="resueltas"] .grupo-cabecera {
  outline: 2px solid var(--color-accent);
  outline-offset: -2px;
}
.grupo-flecha {
  width: 16px; height: 16px;
  flex: none;
  transition: transform var(--duration-fast) var(--ease-out);
}
.grupo-cuenta {
  min-width: 20px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--color-border);
  color: var(--color-fg-secondary);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
}
.grupo-pista {
  margin-left: auto;
  font-weight: var(--weight-regular);
  font-size: var(--text-xs);
  color: var(--color-fg-tertiary);
}
/* «No tienes nada que resolver ahora mismo»: el hueco del primer grupo cuando
   está vacío y abajo sí hay trabajo. Una línea y nada más —sin icono grande y
   sin frase de ánimo—: es un dato, y debajo hay vencidos que perseguir. */
.cola-sin-nada {
  margin: 0;
  padding: 14px 18px;
  border-top: 1px solid var(--color-border);
  color: var(--color-fg-secondary);
  font-size: var(--text-sm);
}

.grupo-lista { display: none; }
/* Cada casilla abre SU grupo: desde el 2026-10-10 hay dos plegados en la
   pestaña «Todas» (Esperando y Resueltas), y abrir uno no abre el otro. */
#verEsperando:checked ~ #inboxContainer [data-grupo="esperando"] .grupo-lista,
#verResueltas:checked ~ #inboxContainer [data-grupo="resueltas"] .grupo-lista { display: block; }
#verEsperando:checked ~ #inboxContainer [data-grupo="esperando"] .grupo-flecha,
#verResueltas:checked ~ #inboxContainer [data-grupo="resueltas"] .grupo-flecha { transform: rotate(90deg); }

/* «Viendo X de Y · quitar filtros». La cabecera contaba el total y la lista
   enseñaba lo filtrado, sin decirlo en ninguna parte. */
.lista-aviso {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 18px;
  border-bottom: 1px solid var(--color-border);
  background: var(--color-accent-softer);
  font-size: var(--text-sm);
  color: var(--color-fg-secondary);
}
.lista-aviso .btn { margin-left: auto; }

/* «Perseguir»: espera fuera y el plazo ya se pasó. La pastilla se retiró de la
   lista el 2026-09-20 —el título del grupo ya lo dice y el motivo lo cuenta la
   pill roja «Vencido» de la fila— y solo se usa ya en el tablero, donde no hay
   grupos. El borde rojo de la fila sí se queda en los dos sitios. */
.badge-perseguir {
  background: var(--color-danger-soft, rgb(179 55 45 / 0.16));
  color: var(--color-danger);
  border: 1px solid var(--color-danger);
}
.ticket-row.es-perseguir::before {
  background: var(--color-danger);
  box-shadow: 0 0 12px var(--color-danger);
}

/* Empty cell helper (cuando no hay valor en columnas) */
.cell-empty {
  display: inline-flex;
  align-items: center;
  width: 14px; height: 1px;
  background: var(--color-fg-muted);
  opacity: 0.4;
  border-radius: 1px;
  vertical-align: middle;
}

/* Skeleton mejorado */
.skel {
  background: linear-gradient(90deg,
    var(--color-surface-muted) 0%,
    rgba(255,255,255,0.18) 50%,
    var(--color-surface-muted) 100%);
  background-size: 200% 100%;
}
html[data-theme="dark"] .skel {
  background: linear-gradient(90deg,
    rgba(255,255,255,0.04) 0%,
    rgba(255,255,255,0.10) 50%,
    rgba(255,255,255,0.04) 100%);
  background-size: 200% 100%;
}

/* Chip improvements */
.chip {
  position: relative;
}
.chip::after {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45);
}
html[data-theme="dark"] .chip::after { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06); }
.chip:hover { transform: translateY(-1px); box-shadow: var(--shadow-1); }
.chip.is-active {
  box-shadow: 0 2px 8px rgb(var(--sombra-tinta) / 0.20);
}

/* Toolbar btn refresh focus */
#btnRefresh, #btnFilters {
  /* `width: auto` para que no los estire la barra. El `min-width: 0` que había
     aquí anulaba el cuadrado de 44 de los iconos-botón: son dos iconos sin
     texto, así que el mínimo se respeta. */
  width: auto; min-width: var(--toque-min);
}

/* ── Shortcut hints overlay ── */
.kbd-overlay {
  position: fixed;
  bottom: 20px; right: 20px;
  background: var(--color-fg);
  color: var(--color-fg-inverse);
  padding: 16px 20px;
  border-radius: var(--radius-lg);
  font-size: var(--text-sm);
  box-shadow: var(--shadow-3);
  z-index: var(--z-modal);
  display: none;
  max-width: 320px;
}
.kbd-overlay.is-visible { display: block; animation: modalIn 200ms var(--ease-spring); }
.kbd-overlay h3 { margin: 0 0 8px; font-size: var(--text-base); font-weight: var(--weight-semibold); }
.kbd-overlay table { font-size: var(--text-sm); border-spacing: 6px 4px; }
.kbd-overlay td:first-child { color: var(--color-fg-muted); padding-right: 8px; }
.kbd-overlay kbd {
  background: rgba(255,255,255,0.1);
  border: 1px solid rgba(255,255,255,0.2);
  color: white;
}

/* ── Casillas de locales (admin) ─────────────────────────────────────────── */
/* 71 locales en columnas: en una sola lista habría que hacer scroll para
   encontrar uno, y en un móvil sería impracticable. */
.casillas-locales {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 4px 12px;
  max-height: 320px;
  overflow-y: auto;
  padding: 10px 12px;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-bg-elevated);
}
.casillas-locales label {
  display: flex; align-items: center; gap: 9px;
  font-size: var(--text-base); color: var(--color-fg-secondary);
  /* Igual que en `.check-item`: se pulsa la fila entera, no la casilla. */
  min-height: var(--toque-min); cursor: pointer;
}
.casillas-acciones { display: flex; gap: 10px; margin-top: 8px; }
.casillas-acciones button {
  background: none; border: 0; padding: 0;
  /* «Marcar todos» / «Ninguno» parecen texto, pero son los dos botones que más
     se pulsan de esta pantalla: se les da alto aunque no se les dé marco. */
  display: inline-flex; align-items: center; min-height: var(--toque-min);
  font: inherit; font-size: var(--text-sm);
  color: var(--color-accent); text-decoration: underline; cursor: pointer;
}

/* ── En vivo: la operación del bot ───────────────────────────────────────── */
.vivo-filtros { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; }
.vivo-rejilla {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 14px;
}

/* El pulso: barras finas por minuto. Los minutos vacíos se DIBUJAN —con una
   marca mínima— porque si no una parada de diez minutos parece actividad
   normal, que es justo lo que uno viene a ver aquí. */
.vivo-pulso {
  display: flex; align-items: flex-end; gap: 2px;
  height: 64px; padding: 4px 0;
}
.vivo-pulso .tramo { flex: 1; height: 100%; display: flex; align-items: flex-end; }
.vivo-pulso .marca {
  width: 100%; background: var(--color-accent);
  border-radius: 2px 2px 0 0; min-height: 2px;
}
.vivo-pulso-pie {
  display: flex; justify-content: space-between;
  font-size: var(--text-xs); color: var(--color-fg-muted);
}
.vivo-tipos { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }

.vivo-eventos { display: flex; flex-direction: column; max-height: 460px; overflow-y: auto; }
.vivo-evento {
  display: grid;
  grid-template-columns: 62px 132px 74px 1fr;
  gap: 10px; align-items: baseline;
  padding: 5px 0;
  border-bottom: 1px solid var(--color-border-soft);
  font-size: var(--text-sm);
}
.vivo-evento .hora { color: var(--color-fg-muted); font-family: var(--font-mono); }
.vivo-evento .tipo {
  color: var(--color-fg-secondary); font-family: var(--font-mono);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Solo el error se colorea: si todo lleva color, el color no avisa de nada. */
.vivo-evento .tipo-error,
.vivo-evento .tipo-invariant_blocked { color: var(--color-danger-fg); font-weight: var(--weight-semibold); }
.vivo-evento .ticket { color: var(--color-fg-tertiary); }
.vivo-evento .que {
  color: var(--color-fg); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

@media (max-width: 700px) {
  .vivo-evento { grid-template-columns: 58px 1fr; }
  .vivo-evento .ticket, .vivo-evento .tipo { grid-column: 2; }
  .vivo-evento .que { grid-column: 1 / -1; white-space: normal; }
}

/* ── Una conversación entera ─────────────────────────────────────────────── */
.conv-hilo { display: flex; flex-direction: column; gap: 8px; }
.conv-linea { display: grid; grid-template-columns: 48px 1fr; gap: 10px; align-items: baseline; }
.conv-linea .hora { font-size: var(--text-xs); color: var(--color-fg-muted); font-family: var(--font-mono); }
.conv-linea .texto {
  padding: 8px 12px; border-radius: var(--radius-lg);
  font-size: var(--text-base); line-height: 1.45;
  white-space: pre-wrap; word-wrap: break-word;
  max-width: 68ch;
}
/* Quién habla se distingue por la POSICIÓN y el fondo, no por un color de
   marca: son dos interlocutores, no dos categorías de dato. */
.conv-cliente .texto { background: var(--color-surface-muted); color: var(--color-fg); }
.conv-bot .texto { background: var(--color-accent-softer); border: 1px solid var(--color-border); }
.conv-evento .texto {
  background: none; padding: 4px 0;
  font-size: var(--text-sm); color: var(--color-fg-tertiary);
  border-top: 1px solid var(--color-border-strong);
  border-radius: 0; max-width: none;
}

/* Cuánto hace del último movimiento del bot. */
.vivo-salud {
  display: flex; gap: 22px; flex-wrap: wrap;
  padding: 10px 14px; margin-bottom: 14px;
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-success);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  font-size: var(--text-sm); color: var(--color-fg-secondary);
}
.vivo-salud strong { color: var(--color-fg); }
/* Más de un día sin un solo evento no es «poco trabajo»: es que algo se paró. */
.vivo-salud.parado {
  border-left-color: var(--color-danger);
  background: var(--color-danger-soft);
  color: var(--color-danger-fg);
}
.vivo-salud.parado strong { color: var(--color-danger-fg); }

/* La configuración del bot: formulario a la izquierda, acciones a la derecha. */
.cfg-columnas { display: grid; grid-template-columns: 1fr; gap: 14px; }
@media (min-width: 900px) {
  .cfg-columnas { grid-template-columns: minmax(0, 1.4fr) minmax(280px, 1fr); align-items: start; }
}

/* ── Una línea, en SVG y sin dependencias ────────────────────────────────── */
.grafico-linea {
  width: 100%; height: 110px; display: block;
  overflow: visible;   /* que las marcas de los extremos no se corten */
}
/* preserveAspectRatio="none" estira el trazo: se compensa con vector-effect
   para que la línea tenga el mismo grosor en toda su longitud. */
.grafico-linea .linea {
  fill: none; stroke: var(--color-accent); stroke-width: 2;
  stroke-linejoin: round; stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
.grafico-linea .area { fill: var(--color-accent-softer); stroke: none; }
.grafico-linea .marca {
  fill: var(--color-accent); stroke: var(--color-bg-elevated); stroke-width: 2;
  vector-effect: non-scaling-stroke;
}
.grafico-linea .marca:hover { r: 5; }
.grafico-vacio {
  height: 110px; display: flex; align-items: center; justify-content: center;
  color: var(--color-fg-muted); font-size: var(--text-sm);
  border: 1px solid var(--color-border-strong); border-radius: var(--radius-md);
}
.grafico-pie {
  display: flex; justify-content: space-between;
  font-size: var(--text-xs); color: var(--color-fg-muted); margin-top: 4px;
}

/* ═══════════════════════════════════════════════════════════════════════════
 * LA MARCA SAONA (restyling, 2026-10-20)
 *
 * Sustituye a «La ficha» (talonario, retícula, troquel de puntos, filete
 * grueso arriba y monoespaciada), que era la identidad propia de ayuda. La
 * guía de diseño manda ahora, y dice poco y claro:
 *
 *   1. Fondo crema (de noche, azul noche); tarjetas en `superficie` con
 *      `borde` y esquinas de 16. Sin retícula ni troquel.
 *   2. Lo que espera una acción lleva el BORDE IZQUIERDO en ocre; lo que
 *      quema, en rojo. Nada más reclama atención.
 *   3. Epicene Text solo en titulares, a 400; ABC Social para el resto.
 *   4. El menú, azul noche con texto crema; lo activo, azul Saona con texto
 *      azul noche.
 * ═══════════════════════════════════════════════════════════════════════════ */

body {
  background-color: var(--fondo);
  background-image: none;
  color: var(--texto);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-cuerpo);
}
body::before { content: none; }
a { color: var(--enlace); }

/* ── Titulares en Epicene ── */
.page-title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 24px;
  line-height: 30px;
  letter-spacing: 0;
  color: var(--texto);
  text-wrap: balance;
  padding-bottom: 0;
}
.page-title::after { content: none; }
/* El saludo de Hoy: «titulo-xl» de la guía, 32/38, un solo uso. */
.hoy-persona .page-title { font-size: 32px; line-height: 38px; }
/* Lo que va dentro de un titular y no es titular (contadores, etiquetas):
   en la sans de la interfaz, no en Epicene. */
.page-title .badge, .page-title .count, h1 .badge, h2 .badge, h2 .count, h3 .badge,
.badge, .chip, .count { font-family: var(--font-sans); }
.page-subtitle { font-size: var(--text-sm); line-height: 20px; color: var(--texto-secundario); }
.card-title, .est-titulo, .section-title, .sol-seccion, .hoy-bloque-titulo, .hoy-seccion h2 {
  font-family: var(--font-display);
  font-size: 19px;
  line-height: 26px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--texto);
}
h1, h2, h3 { font-weight: 400; }

/* Cifras que se comparan: alineadas, en la misma letra. */
.mono, .sol-tarjeta .ref, .vivo-evento .hora, .vivo-evento .ticket,
.est-barra .valor, .est-local .cifras, .grafico-pie {
  font-family: var(--font-sans);
}
/* Las cifras que se comparan en columna, alineadas. Solo ahí: en ABC Social
   el ajuste tabular ensancha también los espacios de una frase. */
.est-barra .valor, .vivo-evento .hora, .grafico-pie { font-variant-numeric: tabular-nums; }
code, pre, kbd { font-family: var(--font-codigo); }

/* ── Tarjetas: superficie, borde, 16 ── */
.card, .sol-tarjeta, .est-local, .est-repetida, .sol-dato {
  background: var(--superficie);
  border: 1px solid var(--borde);
  border-left-width: 1px;
  border-radius: var(--radius-tarjeta);
  box-shadow: none;
  position: relative;
}
.card::after { content: none; }

/* Lo que espera de ti: borde izquierdo ocre. Lo que quema: rojo. Quién la
   tiene (cuando no eres tú): azul, sin pedir nada. */
.sol-tarjeta.pide-respuesta { border-left: 4px solid var(--aviso); }
/* Esperando a alguien de fuera: no te pide nada a ti, así que no va en ocre. */
.pend-externo, .sol-tarjeta.espera-externo { border-left: 4px solid var(--texto-secundario); }
.sol-tarjeta.urgente, .est-local.con-urgentes, .sol-dato.urgentes {
  border-left: 4px solid var(--color-danger);
}
.sol-tarjeta.espera-solicitante, .pend-solicitante { border-left: 4px solid var(--color-info); }
.pend-equipo { border-left: 4px solid var(--texto); }
.pend { border-top-width: 1px; }

.est-local.en-paz { border-color: var(--borde); }
.est-local.en-paz .cifras { color: var(--texto-secundario); }

/* El separador de la cabecera de una tarjeta: una línea fina, no troquel. */
.sol-tarjeta .fila-alta, .est-repetida, .vivo-salud {
  border-bottom: 1px solid var(--borde);
  padding-bottom: 8px;
}
.est-repetida { border-bottom: 1px solid var(--borde); border-top: 1px solid var(--borde); }

a.sol-tarjeta, a.card, .card-hover {
  transition: border-color 0.18s var(--curva-suave), box-shadow 0.18s var(--curva-suave);
}
a.sol-tarjeta:hover, a.card:hover, .card-hover:hover {
  transform: none;
  border-color: var(--borde-control);
  box-shadow: var(--shadow-2);
}

/* ── El menú: azul noche ── */
.app-sidebar {
  background: var(--menu-fondo);
  background-image: none;
  border-right: none;
  color: var(--menu-texto);
}
.app-sidebar .nav-group-label { color: var(--menu-secundario); letter-spacing: 0.08em; }
.app-sidebar .app-nav { scrollbar-color: var(--menu-borde) transparent; }
.app-sidebar .app-nav::-webkit-scrollbar-thumb { background: var(--menu-borde); }
.app-sidebar .nav-item {
  color: var(--crema);
  border-radius: var(--radius-pill);
  font-weight: 500;
  transition: background 0.15s, color 0.15s;
}
.app-sidebar .nav-item:hover { background: var(--menu-hover); color: var(--menu-texto); }
.app-sidebar .nav-item.active {
  background: var(--azul-saona); color: var(--azul-noche);
  border-color: var(--azul-saona);
}
.app-sidebar .nav-item.active .icon { color: var(--azul-noche); }
.app-sidebar .user-card, .app-sidebar .theme-switcher {
  background: var(--menu-hover);
  border-color: var(--menu-borde);
}
.app-sidebar .user-name { color: var(--crema); }
.app-sidebar .avatar { background: var(--azul-saona); color: var(--azul-noche); }
/* Las etiquetas del rol en el menú: sobre el azul noche, en crema. */
.app-sidebar .badge { background: var(--menu-borde); color: var(--menu-texto); }

/* ── El número de lo pendiente en el menú (2026-10-31) ──
   El menú es azul noche de día y de noche, así que el número va en crema con
   texto azul noche en los dos temas (13:1), y sigue leyéndose sobre la
   entrada activa (azul Saona). En la barra de abajo el fondo sí cambia con el
   tema: ahí el número va con los colores del texto, invertidos. Sin número
   lo esconde la regla global de `hidden`, que va con !important. */
.menu-contador {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; height: 22px; padding: 0 7px;
  margin-left: auto;
  border-radius: var(--radius-pill);
  background: var(--crema); color: var(--azul-noche);
  font-size: 13px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.ba-item .menu-contador {
  position: absolute; top: 3px; left: calc(50% + 6px);
  min-width: 18px; height: 18px; padding: 0 5px;
  margin-left: 0;
  font-size: 11px;
  background: var(--texto); color: var(--superficie);
}

/* ── Botones: píldora; el principal, azul Saona con texto azul noche ── */
.btn { border-radius: var(--radius-pill); font-weight: 500; }
.btn-primary {
  background: var(--primario);
  color: var(--texto-sobre-primario);
  border-color: var(--primario);
  box-shadow: none;
}
.btn-primary:hover:not(:disabled) {
  background: var(--primario-hover); color: var(--texto-sobre-primario);
  transform: none; box-shadow: none;
}
.btn-primary .icon { color: currentColor; }
/* Lo pendiente que se pulsa («Confirmar»): ocre con texto azul noche. */
.btn-warning { background: var(--aviso); color: var(--texto-sobre-aviso); }
/* La urgencia «alta» es un estado, no algo pendiente: va en el rojo suave de
   siempre (arriba, `.badge.badge-alta`), no en ocre. */

/* ── Cifras grandes ── */
.sol-dato .valor {
  font-family: var(--font-display);
  font-size: 32px; line-height: 38px; font-weight: 400; letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}
.sol-dato .etiqueta { letter-spacing: 0.02em; }
.est-repetida .veces {
  font-family: var(--font-display);
  font-size: 32px; font-weight: 400; color: var(--texto);
}

/* ── Barras y gráficos: azules de la marca ── */
.est-barra .relleno, .vivo-pulso .marca {
  transform-origin: left center;
  animation: pintar-barra 0.6s var(--curva-entrada) both;
  background: var(--brand-400);
  border-radius: var(--radius-pill);
}
.est-barra:nth-child(1) .relleno { animation-delay: 30ms; background: var(--texto); }
.est-barra:nth-child(2) .relleno { animation-delay: 75ms; }
.est-barra:nth-child(3) .relleno { animation-delay: 120ms; }
.est-barra:nth-child(4) .relleno { animation-delay: 165ms; }
.est-barra:nth-child(5) .relleno { animation-delay: 210ms; }
.est-barra .via { background: var(--superficie-suave); border-radius: var(--radius-pill); }
.grafico-linea .linea {
  stroke: var(--texto);
  stroke-dasharray: 1200; stroke-dashoffset: 1200;
  animation: dibujar-trazo 1.1s var(--curva-suave) 0.15s both;
}
.grafico-linea .area { fill: rgb(122 151 171 / 0.16); animation: aparecer 0.8s var(--curva-entrada) 0.5s both; }
.grafico-linea .marca { fill: var(--primario); stroke: var(--superficie); animation: aparecer 0.4s var(--curva-entrada) 1s both; }

/* El titular del reparto: una nota informativa, no un aviso. */
.est-titular {
  border-left: 4px solid var(--primario);
  background: var(--primario-suave);
  color: var(--texto);
  border-radius: var(--radius-campo);
  font-size: var(--text-sm);
}

/* ── Las tarjetas aparecen ── */
@keyframes imprimir {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.sol-lista > *, .est-locales > *, .est-repetidas > * {
  animation: imprimir 0.36s var(--curva-entrada) both;
}
.sol-lista > *:nth-child(1), .est-locales > *:nth-child(1) { animation-delay: 30ms; }
.sol-lista > *:nth-child(2), .est-locales > *:nth-child(2) { animation-delay: 60ms; }
.sol-lista > *:nth-child(3), .est-locales > *:nth-child(3) { animation-delay: 90ms; }
.sol-lista > *:nth-child(4), .est-locales > *:nth-child(4) { animation-delay: 120ms; }
.sol-lista > *:nth-child(n+5), .est-locales > *:nth-child(n+5) { animation-delay: 150ms; }

/* ── El logo ──
 * El SVG de la marca tal cual: «Ayuda» en blanco y «SAONA» en azul Saona,
 * sobre el azul noche del menú y de la cabecera del móvil. */
.app-logo {
  display: block;
  padding: 4px 8px 16px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--menu-borde);
  text-decoration: none;
}
.app-logo .logo-marca-img { display: block; width: 136px; height: auto; }
.app-logo .logo-troquel, .app-logo .logo-mark { display: none; }

/* Barra de carga: azul Saona. El ocre es solo para lo pendiente. */
#barra-carga { background: var(--primario); }

/* ── La puerta ── */
.login-shell { background: var(--fondo); }
.login-card {
  background: var(--superficie);
  border: 1px solid var(--borde);
  border-radius: var(--radius-tarjeta);
  box-shadow: var(--shadow-1);
}
.login-logo { text-align: left; }
.login-logo .logo-mark, .login-logo .logo-troquel { display: none; }
.login-logo .login-logo-marca { margin: 0 0 4px; line-height: 0; }
.login-logo .login-logo-marca img { width: 168px; height: auto; }
.logo-en-oscuro { display: none; }
html[data-theme="dark"] .logo-en-claro { display: none; }
html[data-theme="dark"] .logo-en-oscuro { display: inline-block; }
.login-logo p {
  margin-top: 12px; font-size: var(--text-base); color: var(--texto-secundario);
}

/* ── ¿Quién la tiene? ── */
.pend-quien {
  font-family: var(--font-display);
  font-size: 19px; line-height: 26px; font-weight: 400;
  color: var(--texto);
}
.pend-desde {
  margin-top: 4px;
  font-size: var(--text-sm); color: var(--texto-secundario);
  font-variant-numeric: tabular-nums;
}
.pend-externo .pend-desde { color: var(--texto-secundario); }
.pend-recorrido {
  margin-top: 8px; display: flex; flex-direction: column; gap: 4px;
  font-size: var(--text-sm); color: var(--texto-secundario);
}
.pend-recorrido .mono { margin-right: 8px; color: var(--texto-secundario); }

/* ── De noche ── la guía ya lo dice en los tokens; aquí solo lo que no es
   un token. */
/* De noche el menú y el fondo son del mismo azul: los separa una línea. */
html[data-theme="dark"] .app-sidebar {
  background: var(--menu-fondo);
  border-right: 1px solid var(--menu-borde);
}

/* Aviso de que el estado «En espera» está apagado en Zendesk. No es un error
   del usuario: es un interruptor que falta, así que se cuenta en gris y no en
   rojo. */
.pend-apagado {
  margin-top: 10px;
  display: flex;
  gap: 8px;
  align-items: flex-start;
  font-size: 12px;
  line-height: 1.45;
  color: var(--color-fg-tertiary);
  border-top: 1px solid var(--color-border);
  padding-top: 10px;
}
.pend-apagado .icon { flex: none; width: 14px; height: 14px; margin-top: 2px; }

/* ═══ AYUDA ══════════════════════════════════════════════════════════════════
 *
 * La página que se abre de pie, con el móvil y con algo roto delante. Manda una
 * regla sobre las demás: **lo que se necesita tiene que poder pulsarse**. Un
 * teléfono que hay que memorizar y marcar en otra aplicación no es ayuda.
 *
 * Por eso aquí no hay tarjetas troqueladas ni inclinaciones: la ficha es
 * tranquila y el número es lo que grita.
 */

.ayuda-buscar {
  position: relative;
  display: flex;
  align-items: center;
  margin-bottom: 26px;
}
.ayuda-buscar > .icon {
  position: absolute;
  left: 14px;
  width: 17px; height: 17px;
  color: var(--color-fg-tertiary);
  pointer-events: none;
}
.ayuda-buscar .field-input {
  width: 100%;
  padding-left: 42px;
  padding-right: 42px;
  height: 46px;
  font-size: 16px;
}
.ayuda-limpiar {
  position: absolute;
  right: 10px;
  display: grid; place-items: center;
  width: 28px; height: 28px;
  border: 0; border-radius: 50%;
  background: var(--color-surface-muted);
  color: var(--color-fg-secondary);
  cursor: pointer;
}
.ayuda-limpiar .icon { width: 14px; height: 14px; }

.ayuda-bloque { margin-bottom: 34px; }

/* «Tu manual» (2026-10-08): arriba de Ayuda, la entrada al manual del rol. Es
   una fila entera y no un enlace pequeño porque es lo que se busca el primer
   día, y la lista de teléfonos de debajo puede ser larga. */
.ayuda-manual { display: flex; flex-direction: column; gap: 8px; margin-bottom: 26px; }
.ayuda-manual-tuyo, .manuales-abrir {
  display: flex; align-items: center; gap: 12px;
  min-height: 56px; padding: 12px 16px;
  border: 1px solid var(--color-border); border-radius: var(--radius-lg);
  background: var(--color-surface); color: var(--color-fg); text-decoration: none;
}
.ayuda-manual-tuyo:hover, .manuales-abrir:hover { border-color: var(--color-accent); }
.ayuda-manual-tuyo > .icon:first-child, .manuales-abrir > .icon:first-child {
  width: 22px; height: 22px; flex: none; color: var(--color-accent);
}
.ayuda-manual-tuyo > span, .manuales-abrir > span { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.ayuda-manual-sub, .manuales-sub { font-size: 14px; color: var(--color-fg-secondary); }
.ayuda-manual-flecha, .manuales-flecha { width: 18px; height: 18px; flex: none; color: var(--color-fg-tertiary); }
.ayuda-manual-todos, .manuales-pdf {
  display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
  min-height: var(--toque-min); padding-inline: 4px;
  font-size: 14px; font-weight: 500; color: var(--color-accent); text-decoration: none;
}
.ayuda-manual-todos .icon, .manuales-pdf .icon { width: 15px; height: 15px; }

.manuales-lista { display: flex; flex-direction: column; gap: 10px; max-width: 720px; }
.manuales-fila { display: flex; align-items: center; gap: 10px; }
.manuales-fila .manuales-abrir { flex: 1; min-width: 0; }
.ayuda-manual-titulo {
  margin: 0 0 2px; font-size: 12px; font-weight: 500; letter-spacing: .08em;
  text-transform: uppercase; color: var(--color-fg-tertiary);
}
.ayuda-manual .manuales-fila { max-width: 720px; }
/* El PDF va al lado de cada manual y con borde de botón (2026-10-08): antes era
   un enlace de texto que se perdía, y es justo lo que el Área viene a buscar
   para pasárselo a un encargado. */
.manuales-pdfs { display: flex; gap: 6px; flex: none; align-self: stretch; }
.manuales-fila .manuales-pdf {
  justify-content: center; align-self: stretch; min-width: 44px; padding-inline: 12px;
  border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-surface);
}
.manuales-fila .manuales-pdf:hover { border-color: var(--color-accent); }
/* «Descargar» fuerza el adjunto, y eso solo sirve donde hay gestor de
   descargas: en el móvil (y en la app instalada, que no tiene ni botón de
   volver) se queda «PDF», que abre el visor desde el que se guarda. */
@media (hover: none) and (pointer: coarse), (display-mode: standalone) {
  .manuales-descargar { display: none !important; }
}
.manuales-generado { margin-top: 22px; max-width: 720px; font-size: 14px; color: var(--color-fg-secondary); }

/* La barra de encima del manual: qué manual es y el PDF. */
.manual-barra {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 16px;
  max-width: 1000px; margin: 0 auto 14px;
}
.manual-barra-texto { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.manual-barra-que { font-size: 12px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; color: var(--color-fg-tertiary); }
.manual-barra-acciones { display: flex; flex-wrap: wrap; gap: 8px; }
.manual-barra-acciones .btn { min-height: var(--toque-min); }

.ayuda-titulo {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0 0 3px;
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--color-fg);
}
.ayuda-titulo .icon { width: 18px; height: 18px; color: var(--texto); }
.ayuda-cuenta {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  color: var(--color-fg-tertiary);
}
.ayuda-que-es {
  margin: 0 0 14px;
  font-size: 14px;
  color: var(--color-fg-tertiary);
}

.ayuda-fichas {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
  gap: 12px;
}

.ayuda-ficha {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 15px 16px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}
.ayuda-ficha-cuerpo { flex: 1; min-width: 0; }
.ayuda-ficha h3 {
  margin: 0 0 7px;
  font-size: 14px;
  font-weight: 500;
  line-height: 1.3;
  color: var(--color-fg);
}

/* El número es lo más grande de la ficha y el único elemento con área de toque
   completa: es a lo que se viene. */
.ayuda-telefono {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 7px 12px 7px 10px;
  margin: 2px 0 4px -2px;
  border-radius: var(--radius-md, 8px);
  background: var(--primario-suave);
  color: var(--color-accent);
  font-family: var(--font-mono);
  font-size: 16px;
  font-weight: 500;
  letter-spacing: 0.01em;
  text-decoration: none;
}
.ayuda-telefono .icon { width: 15px; height: 15px; }

.ayuda-detalle {
  margin: 0 0 4px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--color-fg-secondary);
  white-space: pre-line;
}
.ayuda-nota {
  margin: 0;
  font-size: 12px;
  line-height: 1.45;
  color: var(--color-fg-tertiary);
}
.ayuda-enlace {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--toque-min);
  padding-inline: 2px;
  margin-top: 6px;
  font-size: 14px;
  font-weight: 500;
  color: var(--color-accent);
  text-decoration: none;
}
.ayuda-enlace .icon { width: 13px; height: 13px; }

.ayuda-sin-nada {
  margin: 0;
  padding: 14px 0;
  font-size: 14px;
  color: var(--color-fg-tertiary);
}

/* Lo archivado solo lo ve quien edita, y se ve que está apagado. */
.ayuda-apagada { opacity: 0.55; border-style: dashed; }
.ayuda-etiqueta {
  margin-left: 6px;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--color-surface-muted);
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-fg-tertiary);
  vertical-align: middle;
}

/* El lápiz no compite con el contenido: se asoma y se aparta. */
.ayuda-editar > summary {
  display: grid; place-items: center;
  width: var(--toque-min); height: var(--toque-min);
  margin: -7px -8px 0 0;
  flex: none;
  list-style: none;
  border-radius: 50%;
  color: var(--color-fg-tertiary);
  cursor: pointer;
}
.ayuda-editar > summary::-webkit-details-marker { display: none; }
.ayuda-editar > summary:hover { background: var(--color-surface-muted); color: var(--color-fg); }
.ayuda-editar > summary .icon { width: 14px; height: 14px; }
.ayuda-editar[open] {
  position: absolute;
  z-index: 20;
  margin-top: 34px;
  margin-left: -250px;
  width: 292px;
  padding: 14px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  box-shadow: 0 14px 34px rgb(var(--sombra-tinta) / 0.16);
}
.ayuda-editar[open] > summary { position: absolute; top: 8px; right: 8px; }

.ayuda-form .field { margin-bottom: 9px; }
.ayuda-form-pie {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 12px;
}
/* En el móvil, los botones del pie uno debajo de otro y a todo el ancho: con
   tres («Guardar y añadir una encuesta», 2026-11-06) el último se salía. */
@media (max-width: 600px) {
  .ayuda-form-pie > .btn { flex: 1 1 100%; justify-content: center; }
}
.ayuda-check {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--color-fg-secondary);
}
.ayuda-form-archivar { margin-top: 10px; display: flex; gap: 16px; flex-wrap: wrap; }
.ayuda-correo { overflow-wrap: anywhere; }
.ayuda-archivar {
  min-height: var(--toque-min);
  min-width: var(--toque-min);
  border: 0; background: none; padding: 0;
  font-size: 12px; color: var(--color-danger);
  cursor: pointer; text-decoration: underline;
}
.ayuda-firma {
  margin: 9px 0 0;
  font-size: 12px;
  color: var(--color-fg-tertiary);
}
.field-opcional {
  font-weight: 400;
  font-size: 12px;
  color: var(--color-fg-tertiary);
}

.ayuda-nueva {
  margin-top: 26px;
  padding-top: 20px;
  border-top: 1px solid var(--color-border);
}
.ayuda-nueva > summary {
  display: inline-flex; align-items: center; gap: 7px;
  min-height: var(--toque-min);
  font-size: 14px; font-weight: 500;
  color: var(--color-accent);
  cursor: pointer;
}
.ayuda-nueva > summary .icon { width: 15px; height: 15px; }
.ayuda-nueva .ayuda-form { max-width: 440px; margin-top: 14px; }

/* En el móvil la ficha ocupa el ancho y el panel de edición deja de flotar:
   ahí no hay sitio para un desplegable de 292px colgando a la izquierda. */
@media (max-width: 640px) {
  .ayuda-fichas { grid-template-columns: 1fr; }
  .ayuda-editar[open] {
    position: static;
    width: auto;
    margin: 10px 0 0;
    box-shadow: none;
  }
  .ayuda-editar[open] > summary { position: static; }
}

/* Para quién es una ficha. Solo aparece cuando NO es de todos: una marca
   «para todos» en el 90% de las tarjetas sería ruido puro. */
.ayuda-para {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin: 7px 0 0;
  padding: 3px 8px 3px 6px;
  border-radius: 4px;
  background: var(--color-surface-muted);
  font-size: 12px;
  font-weight: 500;
  color: var(--color-fg-secondary);
}
.ayuda-para .icon { width: 12px; height: 12px; flex: none; }

/* El reparto va plegado: la inmensa mayoría de las fichas son para todos y ese
   caso no debe costar ni un clic. */
.ayuda-ambito {
  margin-top: 12px;
  padding-top: 11px;
  border-top: 1px solid var(--color-border);
}
.ayuda-ambito > summary {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: var(--toque-min);
  font-size: 12px; font-weight: 500;
  color: var(--color-fg-secondary);
  cursor: pointer;
}
.ayuda-ambito > summary .icon { width: 13px; height: 13px; }
.ayuda-ambito[open] { padding-bottom: 4px; }
.ayuda-ambito[open] > summary { margin-bottom: 10px; }

/* ── Teléfonos con horario (2026-10-06) ──
   Lo que vale AHORA va en grande y es lo único que grita; el resto de números
   va plegado en «Otros horarios», porque a las once de la noche nadie tiene
   que leer el horario de oficina para saber a quién llamar. */
.tel-ahora { margin: 0 0 4px; }
.tel-ahora-quien {
  margin: 0 0 2px;
  font-size: 12px;
  color: var(--color-fg-secondary);
}
.tel-ahora-quien strong { color: var(--color-fg); font-weight: 500; }
.tel-sin {
  display: flex; align-items: center; gap: 7px;
  margin: 2px 0 2px;
  font-size: 14px; font-weight: 500;
  color: var(--color-fg-secondary);
}
.tel-sin .icon { width: 15px; height: 15px; color: var(--color-fg-tertiary); }
.tel-proximo {
  margin: 0 0 4px;
  font-size: 14px;
  color: var(--color-fg-tertiary);
}

.tel-otros { margin: 2px 0 6px; }
.tel-otros > summary {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: var(--toque-min);
  font-size: 14px; font-weight: 500;
  color: var(--color-accent);
  cursor: pointer;
  list-style: none;
}
.tel-otros > summary::-webkit-details-marker { display: none; }
.tel-otros > summary .icon { width: 13px; height: 13px; }
.tel-lista {
  display: grid; gap: 8px;
  margin: 0; padding: 0; list-style: none;
}
.tel-item {
  display: grid; gap: 1px;
  padding: 8px 10px;
  border-radius: var(--radius-md, 8px);
  background: var(--color-surface-muted);
}
.tel-item-vale { box-shadow: inset 3px 0 0 var(--color-accent); }
.tel-item-cabeza { display: flex; align-items: center; gap: 8px; }
.tel-item-etq { font-size: 14px; font-weight: 500; color: var(--color-fg); }
.tel-item-ahora {
  padding: 1px 6px;
  border-radius: 4px;
  background: var(--primario-suave);
  color: var(--color-accent);
  font-size: 12px; font-weight: 500;
}
.tel-item-num {
  display: inline-flex; align-items: center;
  min-height: var(--toque-min);
  font-family: var(--font-mono);
  font-size: 14px; font-weight: 500;
  color: var(--color-fg);
  text-decoration: none;
  overflow-wrap: anywhere;
}
a.tel-item-num { color: var(--color-accent); }
.tel-item-cuando { font-size: 12px; color: var(--color-fg-secondary); }

/* El editor de números. Cada número es una caja; los días son fichas de 44 px
   que se pulsan con el pulgar, no casillas de 13 px. */
.tel-editor { margin: 4px 0 10px; }
.tel-editor[hidden], .tel-franjas[hidden], [data-tipo-no][hidden] { display: none; }
.tel-nums { display: grid; gap: 10px; }
.tel-num {
  min-width: 0;
  margin: 0;
  padding: 10px 10px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  background: var(--color-surface-muted);
}
.tel-num-cabeza { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
.tel-num-titulo {
  margin: 0;
  font-size: 12px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--color-fg-tertiary);
}
.tel-num-acciones { display: flex; gap: 2px; }
.tel-boton {
  display: grid; place-items: center;
  width: var(--toque-min); height: var(--toque-min);
  flex: none;
  border: 0; border-radius: 50%;
  background: none;
  color: var(--color-fg-secondary);
  cursor: pointer;
}
.tel-boton:hover { background: var(--color-surface); color: var(--color-fg); }
.tel-boton .icon { width: 15px; height: 15px; }
.tel-quitar:hover { color: var(--color-danger); }
.tel-num-datos { display: grid; gap: 0 10px; grid-template-columns: 1fr; }
.tel-num-datos .field { display: block; margin-bottom: 8px; }
.tel-num-datos .field-input { width: 100%; min-height: var(--toque-min); }

.tel-modos { display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 8px; }
.tel-modo { position: relative; }
.tel-modo input { position: absolute; opacity: 0; pointer-events: none; }
.tel-modo span {
  display: inline-flex; align-items: center;
  min-height: var(--toque-min);
  padding: 0 12px;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  background: var(--color-surface);
  font-size: 14px; color: var(--color-fg-secondary);
  cursor: pointer;
}
.tel-modo input:checked + span {
  border-color: var(--color-accent);
  background: var(--primario-suave);
  color: var(--color-accent);
  font-weight: 500;
}
.tel-modo input:focus-visible + span,
.tel-dia input:focus-visible + span { outline: 2px solid var(--color-accent); outline-offset: 2px; }

.tel-franja {
  padding: 8px 0 10px;
  border-top: 1px solid var(--color-border);
}
.tel-dias { display: flex; flex-wrap: wrap; gap: 4px; }
.tel-dia { position: relative; }
.tel-dia input { position: absolute; opacity: 0; pointer-events: none; }
.tel-dia span[aria-hidden] {
  display: grid; place-items: center;
  width: var(--toque-min); height: var(--toque-min);
  border: 1px solid var(--color-border);
  border-radius: 50%;
  background: var(--color-surface);
  font-size: 14px; font-weight: 500;
  color: var(--color-fg-secondary);
  cursor: pointer;
}
.tel-dia input:checked + span {
  border-color: var(--color-accent);
  background: var(--primario-suave);
  color: var(--color-accent);
}
.tel-oculto {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}
.tel-atajos { display: flex; flex-wrap: wrap; gap: 4px; margin: 6px 0; }
.tel-atajo {
  min-height: var(--toque-min);
  min-width: var(--toque-min);
  padding: 0 10px;
  border: 0; border-radius: 6px;
  background: none;
  font-size: 12px; font-weight: 500;
  color: var(--color-accent);
  cursor: pointer;
}
.tel-atajo:hover { background: var(--color-surface); }
.tel-horas { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
/* `display: flex` le gana a `[hidden]`: sin esto «Todo el día» no escondería las horas. */
.tel-hora[hidden] { display: none; }
.tel-todo {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: var(--toque-min); font-size: 14px; color: var(--color-fg-secondary);
}
.tel-hora {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 14px; color: var(--color-fg-secondary);
}
.tel-hora .field-input { width: 7.5em; min-height: var(--toque-min); }
.tel-anadir {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: var(--toque-min);
  padding: 0 4px;
  border: 0; background: none;
  font-size: 14px; font-weight: 500;
  color: var(--color-accent);
  cursor: pointer;
}
.tel-anadir .icon { width: 14px; height: 14px; }
.tel-aviso {
  margin: 6px 0 10px;
  font-size: 12px; line-height: 1.45;
  color: var(--color-fg-tertiary);
}
.tel-previa-caja {
  padding: 10px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
}
.tel-previa-titulo {
  margin: 0 0 6px;
  font-size: 12px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--color-fg-tertiary);
}
.tel-previa:empty::before {
  content: "Escribe un número para verlo aquí.";
  font-size: 12px; color: var(--color-fg-tertiary);
}
.tel-previa-errores {
  margin: 0 0 8px; padding: 8px 10px 8px 26px;
  border-radius: 6px;
  background: var(--color-danger-soft);
  color: var(--color-danger-fg);
  font-size: 12px; line-height: 1.45;
}

/* Editar un teléfono no cabe en el desplegable de 292 px: con sus números
   abiertos la ficha ocupa la fila entera y el formulario se pinta dentro. */
.ayuda-ficha:has(> .ayuda-editar[open] [data-es-tel]) {
  grid-column: 1 / -1;
  flex-wrap: wrap;
}
.ayuda-ficha:has(> .ayuda-editar[open] [data-es-tel]) > .ayuda-editar[open] {
  position: relative;
  flex: 1 1 100%;
  width: auto;
  margin: 10px 0 0;
  box-shadow: none;
}
@media (min-width: 560px) {
  .tel-num-datos { grid-template-columns: 1fr 1fr; }
}

/* Las pantallas de acceso que no son el login: olvidé mi contraseña y elegir
   clave. Comparten la caja del login y solo añaden texto explicativo. */
.acceso-texto {
  margin: 0 0 18px;
  font-size: 14px;
  line-height: 1.55;
  color: var(--color-fg-secondary);
}
.acceso-menudo {
  display: inline-flex; align-items: center; min-height: 44px;
  font-size: 14px;
  line-height: 20px;
  color: var(--enlace);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.acceso-aviso {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 11px 13px;
  margin-bottom: 16px;
  border-radius: var(--radius-lg);
  background: var(--color-surface-muted);
  border: 1px solid var(--color-border);
  font-size: 14px;
  line-height: 1.5;
  color: var(--color-fg-secondary);
}
.acceso-aviso .icon { width: 15px; height: 15px; flex: none; margin-top: 1px; }
.acceso-aviso-mal {
  background: var(--color-danger-soft);
  border-color: var(--color-danger);
  color: var(--color-danger-fg);
}

/* La nota bajo un campo del formulario: explica la consecuencia de lo que se
   va a escribir, antes de escribirlo. */
.campo-nota {
  margin: 5px 0 0;
  font-size: 12px;
  line-height: 1.45;
  color: var(--color-fg-tertiary);
}

/* Los avisos en el móvil. Van al final de Ayuda: es lo último que se mira, no
   lo primero, y quien viene a por un teléfono no debe tropezarse con esto. */
.avisos {
  margin-top: 30px;
  padding-top: 22px;
  border-top: 1px solid var(--color-border);
}
.avisos-botones { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.avisos-dice {
  margin: 10px 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--color-fg-tertiary);
}
.avisos-mal { color: var(--color-danger-fg); }

/* El interruptor de los avisos. Un `checkbox` de verdad debajo, para que
   funcione con teclado y con lector de pantalla; lo que se ve es la palanca. */
.avisos-switch {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 14px;
  cursor: pointer;
  user-select: none;
}
.avisos-switch input {
  position: absolute;
  opacity: 0;
  width: 44px; height: 26px;
  margin: 0;
  cursor: pointer;
}
.avisos-palanca {
  position: relative;
  flex: none;
  width: 44px; height: 26px;
  border-radius: 13px;
  background: var(--color-surface-muted);
  border: 1px solid var(--color-border);
  transition: background 0.18s var(--curva-entrada), border-color 0.18s;
}
.avisos-palanca::after {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--color-surface);
  box-shadow: 0 1px 3px rgb(var(--sombra-tinta) / 0.22);
  transition: transform 0.18s var(--curva-entrada);
}
.avisos-switch input:checked + .avisos-palanca {
  background: var(--primario);
  border-color: var(--borde-control);
}
.avisos-switch input:checked + .avisos-palanca::after { transform: translateX(18px); }
.avisos-switch input:focus-visible + .avisos-palanca {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
.avisos-switch input:disabled + .avisos-palanca { opacity: 0.55; }
.avisos-etiqueta { font-size: 14px; color: var(--color-fg); }
.avisos-probar { margin-top: 12px; }

/* ═══ QUE PAREZCA UNA APP ════════════════════════════════════════════════════
 *
 * Todo esto es para el iPhone abierto desde el icono, sin barra de navegador.
 * Ahí, lo que en un ordenador es «una web que se ve bien en móvil» se nota
 * enseguida que es una web metida dentro de un marco.
 *
 * Cuatro cosas lo arreglan, y ninguna es decorativa:
 *
 *  1. Las zonas seguras. Con `black-translucent` la página se dibuja DEBAJO de
 *     la barra de estado y del indicador de inicio. Sin `env(safe-area-inset-*)`
 *     el contenido queda cortado por arriba y por abajo — eso es la «ventana
 *     descuadrada».
 *  2. Navegación abajo. En iOS lo de arriba es contexto y lo de abajo es
 *     navegación, porque es donde llega el pulgar.
 *  3. Nada se sale de ancho, nunca. En una app, el desplazamiento lateral no
 *     existe; en cuanto aparece, se nota que es una web.
 *  4. Los detalles del navegador que delatan: el destello azul al tocar, el
 *     rebote al llegar al final, el texto que crece al girar el teléfono.
 */

/* ── 3. Nada se sale de ancho ──────────────────────────────────────────────
 *
 * OJO: aquí había `overflow-x: hidden` en html y body, y fue un error.
 *
 * En iOS eso **rompe `position: fixed`**: la barra de abajo dejaba de estar
 * fija y se desplazaba con el contenido. Es un fallo conocido de Safari y lo
 * introduje yo al intentar tapar el desplazamiento lateral.
 *
 * La forma correcta es no tener nada que se salga. Las tablas —lo único que
 * legítimamente necesita más ancho— van en su propio contenedor con
 * `overflow-x:auto`, y `min-width:0` deja que las rejillas encojan de verdad en
 * vez de empujar hacia los lados. */
html, body { max-width: 100%; }
/* Un hijo de flex o grid no baja de su tamaño mínimo de contenido salvo que se
   le diga. Es la causa silenciosa de casi todo desbordamiento lateral. */
.app-main, .app-shell > * { min-width: 0; }

/* ── 4. Los detalles que delatan ─────────────────────────────────────────── */
body {
  /* Safari agranda el texto al girar a horizontal. En una app, no. */
  -webkit-text-size-adjust: 100%;
  /* El destello azul al tocar cualquier cosa es de navegador, no de app. */
  -webkit-tap-highlight-color: transparent;
}
/* El rebote elástico al llegar al final delata la web. Se quita del armazón,
   no del documento: dentro, una lista larga sí debe poder rebotar. */
.app-shell { overscroll-behavior-y: none; }

@media (max-width: 768px) {
  /* El armazón CLAVADO al hueco visible, y nada más puede desplazarse.
   *
   * Con `height: 100dvh` seguía moviéndose la barra, y el motivo es que el
   * `body` aún podía desplazarse unos píxeles por su cuenta: basta un margen o
   * un elemento suelto al final para que toda la pantalla se arrastre un poco
   * con el rebote del dedo.
   *
   * `position: fixed; inset: 0` no deja margen a eso: el armazón ES el hueco
   * visible, exactamente, y lo único que se desplaza es el contenido de dentro.
   * Además desaparece la dependencia de `dvh`, que en iOS cambia de valor
   * cuando el sistema decide.
   *
   * El cajón lateral sigue funcionando: un ancestro `fixed` no cambia dónde se
   * anclan sus descendientes `fixed` —solo lo haría un `transform`—. */
  html, body { height: 100%; overflow: hidden; }
  .app-shell {
    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
  }

  /* El papel se pinta en el CONTENIDO, no en el fondo de la página.
   *
   * Es el otro motivo de que se viera el hueco: el fondo era papel y la barra
   * blanca, así que cualquier franja que asomara por debajo —un píxel de
   * redondeo, un fotograma de retraso— cantaba. Poniendo el fondo del color de
   * la barra, lo que asome es invisible. */
  body { background: var(--color-surface); }
  .app-main { background: var(--color-bg); }
  .mobile-topbar { flex: none; position: static; }
  .app-main {
    flex: 1 1 auto;
    overflow-y: auto;
    /* La inercia del dedo. Sin esto el desplazamiento va a tirones y se nota
       que no es una app. */
    -webkit-overflow-scrolling: touch;
    /* Aquí sí: el rebote se queda dentro del contenido y no arrastra la
       pantalla entera. */
    overscroll-behavior-y: contain;
    /* Red de seguridad, no el arreglo: con `overflow-y: auto` el eje x pasa a
       `auto` solo, y cualquier cosa que se saliera unos píxeles dejaba
       arrastrar toda la pantalla de lado (2026-10-10). Lo que se sale se
       arregla en su sitio; esto solo impide que el dedo lo note. */
    overflow-x: clip;
  }

  /* ── 1. Zonas seguras ─────────────────────────────────────────────────── */
  .mobile-topbar {
    padding-top: max(12px, env(safe-area-inset-top));
    padding-bottom: 12px;
    padding-left: max(16px, env(safe-area-inset-left));
    padding-right: max(16px, env(safe-area-inset-right));
    /* La cabecera oscura de la guía, con el logo tal cual. */
    background: var(--menu-fondo);
    border-bottom: 1px solid var(--menu-borde);
  }
  .app-main {
    padding-left: max(14px, env(safe-area-inset-left));
    padding-right: max(14px, env(safe-area-inset-right));
    /* Sin hueco extra para la barra: ya no flota sobre el contenido, está
       debajo de él. Solo un respiro al final. */
    padding-bottom: 24px;
  }

  /* La marca, en el idioma nuevo: el «S» de antes era del panel viejo. */
  /* El logo de la marca: «Ayuda» en blanco y «SAONA» en azul Saona. */
  .topbar-marca { display: inline-flex; align-items: center; min-height: 44px; }
  .topbar-marca img { display: block; width: 84px; height: auto; }

  /* ── 2. La barra de abajo ───────────────────────────────────────────────
   *
   * NO va `fixed`, y eso es el arreglo de que «a veces se desajusta».
   *
   * Una barra fija sobre una página que se desplaza entera se desalinea en iOS
   * en cuanto hay rebote al final, o cuando el teclado cambia el alto de la
   * ventana. Se pelea con el navegador en cada fotograma.
   *
   * Aquí el armazón ocupa la pantalla y NO se desplaza; lo que se desplaza es
   * solo el contenido. La barra está en su sitio porque es el último hijo de
   * una caja que no se mueve, no porque se lo digamos. Así es como se comporta
   * una app de verdad: la navegación no es parte del documento que scrollea.
   */
  .barra-abajo {
    position: static;
    flex: none;
    z-index: var(--z-mobile-bar);
    display: flex;
    /* Fondo sólido, sin `backdrop-filter`.
       El desenfoque queda precioso y en iOS obliga a repintar el área entera en
       cada fotograma del desplazamiento: es la diferencia entre ir fino y ir a
       tirones. Una barra de navegación no puede costar fotogramas. */
    background: var(--color-surface);
    border-top: 1px solid var(--color-border);

    /* La franja de debajo es la zona del indicador de inicio: la barra se
       extiende ahí para que los iconos no queden donde el dedo tropieza con la
       raya del sistema. Es lo que hacen las apps nativas.

       En Android (29-oct-2026) el hueco es la barra de botones del sistema
       (■ ● ◀, ~48 px): Chrome pinta la app por debajo de ella («de borde a
       borde») y la zona segura es esa barra entera. Recortarla dejaba nuestra
       barra tapada por los botones del sistema: «la parte de abajo
       desaparece». Así que, por defecto, el hueco entero. */
    padding-bottom: env(safe-area-inset-bottom, 0px);

    /* Su propia capa de pintado.
       Sin esto, iOS repinta la barra con retraso durante el desplazamiento por
       inercia y se ve «despegarse» del borde un instante: no es que se mueva,
       es que se pinta tarde. Aquí es seguro —la barra ya no es `fixed`, así que
       el `transform` no cambia dónde se ancla nada—. */
    transform: translateZ(0);
    backface-visibility: hidden;
  }
  /* Solo en iOS: su hueco es el indicador de inicio (34 px) y se lee como
     espacio muerto; con 18 el dedo sigue despejado y la barra no parece hueca.
     `-webkit-touch-callout` solo existe en el WebKit de iOS. */
  @supports (-webkit-touch-callout: none) {
    .barra-abajo { padding-bottom: min(env(safe-area-inset-bottom), 18px); }
  }
  .ba-item {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    /* 46px de alto: por debajo de 44 el dedo falla, y eso se nota más que
       cualquier color. Con poco relleno abajo, la etiqueta queda pegada a la
       franja del indicador y las dos se leen como una sola pieza. */
    min-height: 46px;
    padding: 7px 4px 3px;
    border: 0;
    background: none;
    font: inherit;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.01em;
    color: var(--color-fg-tertiary);
    text-decoration: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .ba-item svg { width: 21px; height: 21px; stroke-width: 1.9; }
  .ba-item.activo { color: var(--color-fg); }
  .ba-item.activo svg { stroke-width: 2.3; }
  /* La pastilla azul Saona bajo el icono activo: dice dónde estás sin depender del
     color del icono, que en escala de grises se pierde. */
  .ba-item { position: relative; }
  .ba-item.activo::before {
    content: "";
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 26px; height: 3px;
    border-radius: 0 0 3px 3px;
    background: var(--primario);
  }
  .ba-item:active { opacity: 0.55; }

  /* El cajón lateral, por encima de la barra de abajo y respetando el notch. */
  .app-sidebar {
    padding-top: max(18px, env(safe-area-inset-top));
    padding-bottom: max(18px, env(safe-area-inset-bottom));
    z-index: calc(var(--z-sidebar) + 1);
  }
  .sidebar-backdrop { z-index: var(--z-sidebar); }
}

/* En el ordenador, la barra de abajo no existe. */
@media (min-width: 769px) {
  .barra-abajo { display: none; }
}

/* Instalada como app, el pulsado largo no debe ofrecer «copiar enlace» ni
   seleccionar el texto de la navegación: eso es de páginas, no de apps. */
@media (display-mode: standalone) {
  .barra-abajo, .mobile-topbar, .app-sidebar {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
  }
}


/* Las tablas son lo único que legítimamente necesita más ancho que el móvil.
 * Se les da su propio desplazamiento en vez de arrastrar la página entera:
 * `overflow-x` en el `html` esconde el problema, esto lo resuelve.
 *
 * `-webkit-overflow-scrolling` es lo que hace que el gesto tenga inercia. Sin
 * él la tabla se arrastra a tirones y se nota que no es una app. */
.tabla-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  /* Sin esto, una celda larga estira la tabla y el `auto` no llega a activarse. */
  max-width: 100%;
}
.tabla-scroll > table { min-width: max-content; }

/* ═══ HOY Y LOS COMUNICADOS ══════════════════════════════════════════════════
 *
 * La portada de quien trabaja en un local. Una lista de cosas que leer, no un
 * cuadro de mandos: lo que se busca aquí es enterarse, no analizar.
 */

.hoy-vacio {
  text-align: center;
  padding: 44px 20px 32px;
  color: var(--color-fg-tertiary);
}
.hoy-vacio .icon { width: 30px; height: 30px; opacity: 0.5; }
.hoy-vacio p { margin: 12px 0 0; font-size: 14.5px; }
.hoy-vacio-nota {
  max-width: 340px;
  margin: 8px auto 0 !important;
  font-size: 14px;
  line-height: 1.55;
}

/* La tarjeta de un comunicado. Sin sombra y sin inclinación: esto se lee de
   arriba abajo, y cada adorno es una milésima de atención que se va. */
.com-tarjeta {
  position: relative;
  display: block;
  padding: 15px 17px;
  margin-bottom: 10px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  text-decoration: none;
  color: inherit;
}
.com-tarjeta:active { background: var(--color-surface-muted); }
.com-tarjeta h2 {
  margin: 0;
  font-size: 16px;
  font-weight: 500;
  line-height: 1.35;
  color: var(--color-fg);
  /* Sitio para el punto de «sin leer», que va en la esquina. */
  padding-right: 18px;
}
/* La cabecera de la tarjeta: el tipo, las marcas, el clip y la fecha.
 *
 * `flex-wrap` no es un adorno. Con cuatro etiquetas —comunicado, fijado,
 * importante y el clip— en un iPhone de 390 px no caben en una línea, y sin
 * envolver la fecha se salía de la tarjeta: se veía «19/0» pegado al borde o
 * directamente cortado. Envolviendo, baja a la línea siguiente y se lee
 * entera. */
.com-cabeza {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 8px;
  margin-bottom: 7px;
}
/* El clip y la fecha, juntos y a la derecha. Es un solo elemento de la
   cabecera para que al envolver bajen los dos: la fecha sola en la línea de
   abajo y pegada a la izquierda se lee como un dato suelto de otra cosa. */
.com-cola {
  display: inline-flex; align-items: center; gap: 8px;
  margin-left: auto; flex: none;
}
.com-fecha {
  flex: none;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--color-fg-tertiary);
}
.com-avance {
  margin: 6px 0 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--color-fg-secondary);
}

/* Sin leer: un punto ámbar y la tinta más marcada. Dos señales y no solo el
   color, que en escala de grises o con daltonismo desaparece. */
.com-punto {
  position: absolute;
  top: 15px; right: 15px;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--ambar);
}
.com-sin-leer h2 { font-weight: 500; }
.com-sin-leer { border-color: var(--color-border-strong); }

/* Importante: una regla lateral, no un fondo de color. Un fondo rojo entero
   grita igual la primera vez que la décima, y a la décima ya no se lee. */
/* Importante no es pendiente: el borde va en el azul de la marca. Lo que está
   sin leer lleva su punto ocre. */
.com-importante { border-left: 4px solid var(--primario); }
.com-marca {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px 2px 6px;
  border-radius: 4px;
  background: var(--ambar-suave);
  color: var(--ambar-texto);
  font-size: 12px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.com-marca svg { width: 12px; height: 12px; }
.com-marca.peq { font-size: 12px; margin-left: 6px; vertical-align: middle; }

.hoy-mas {
  margin: 2px 0 0;
  font-size: 12px;
  color: var(--color-fg-tertiary);
}
.hoy-bloque {
  margin-top: 30px;
  padding-top: 20px;
  border-top: 1px solid var(--color-border);
}
.hoy-acciones { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }

/* ── El comunicado abierto ─────────────────────────────────────────────── */
.com-volver { margin: 0 0 14px; }
.com-volver a {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 14px; color: var(--color-fg-secondary); text-decoration: none;
}
.com-volver svg { width: 15px; height: 15px; }
.com-detalle { max-width: 640px; }
.com-detalle h1 {
  margin: 10px 0 6px;
  font-family: var(--font-display);
  font-size: 25px;
  font-weight: 400;
  line-height: 1.22;
  letter-spacing: 0;
  color: var(--color-fg);
}
.com-firma {
  margin: 0 0 20px;
  font-size: 12px;
  color: var(--color-fg-tertiary);
}
.com-cuerpo {
  /* El cuerpo llega ya convertido por `comunicados/formato.py`: párrafos,
     `<br>`, listas, títulos y enlaces, todo con etiquetas que pone la casa y
     el texto del autor escapado. Ya no hace falta `pre-line`: los saltos son
     `<br>` y un `pre-line` duplicaría los de entre etiquetas. */
  font-size: 16px;
  line-height: 1.65;
  color: var(--color-fg);
  overflow-wrap: anywhere;
}
.com-cuerpo p { margin: 0 0 12px; }
.com-cuerpo > :last-child { margin-bottom: 0; }
.com-cuerpo .fmt-titulo {
  margin: 22px 0 8px;
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: 0;
  color: var(--color-fg);
}
.com-cuerpo > .fmt-titulo:first-child { margin-top: 0; }
.com-cuerpo .fmt-lista { margin: 0 0 12px; padding-left: 22px; }
.com-cuerpo .fmt-lista li { margin: 0 0 4px; }
.com-cuerpo .fmt-lista li::marker { color: var(--color-fg-secondary); }
.com-cuerpo strong { font-weight: 500; }
/* El resaltado: los cuatro colores de `formato.RESALTADOS`, los mismos que
   lleva el correo en línea. Fondo claro y letra oscura TAMBIÉN de noche: un
   rotulador con letra clara no se lee, y uno oscuro deja de parecer un
   rotulador (Victor, 2026-10-08). */
.fmt-resaltado {
  padding: 0 2px;
  border-radius: 2px;
  color: var(--azul-noche);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.fmt-r-amarillo { background: #fff1a6; }
.fmt-r-verde    { background: #c9f0d3; }
.fmt-r-celeste  { background: #c8ecfb; }
.fmt-r-rosa     { background: #fbd3e4; }
.com-cuerpo .fmt-resaltado .fmt-enlace { color: var(--azul-noche); }
.com-cuerpo .fmt-enlace {
  color: var(--color-accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  font-weight: 500;
}
/* Una dirección suelta es una ristra sin espacios: sin esto empuja la
   pantalla de lado en un iPhone. */
.com-cuerpo .fmt-url { word-break: break-all; font-weight: 500; }
.com-enlace { margin-top: 20px; }

/* ── La lista de quien publica ─────────────────────────────────────────── */
.com-fila {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 0;
  border-bottom: 1px solid var(--color-border);
}
.com-fila-cuerpo { flex: 1; min-width: 0; }
.com-fila h2 { margin: 0 0 4px; font-size: 14.5px; font-weight: 500; }
.com-estado { margin: 0; font-size: 12px; color: var(--color-fg-tertiary); }
.com-fila-acciones { display: flex; align-items: flex-start; gap: 8px; flex: none; }

/* Las dos fechas de una publicación, una al lado de otra.
 * Juntas se leen como lo que son —un principio y un final— y separadas
 * parecían dos ajustes sin relación. En el móvil, una debajo de otra. */
.pub-fechas { display: flex; gap: 12px; }
.pub-fechas .field { flex: 1; min-width: 0; }
@media (max-width: 560px) { .pub-fechas { flex-direction: column; gap: 0; } }

/* ── El formulario de publicar, también en un iPhone ───────────────────────
 *
 * El de CREAR desbordaba por la derecha y el de EDITAR no, con los mismos
 * campos: la diferencia era el envoltorio. El de editar vive en una `.card`,
 * que es un bloque normal y da el ancho a sus hijos; el de crear vive dentro
 * de un `<details>` y llevaba su ancho máximo en un `style=` en línea, sin un
 * `width` que lo obligara a encoger. Con un control que trae ancho propio
 * —en iOS el de fecha y el de fichero lo traen, y es la lección que ya se
 * pagó en Personal (ver solicitante.css)— el formulario entero se hace más
 * ancho que el teléfono y la pantalla se arrastra de lado.
 *
 * Así que los dos formularios llevan la misma clase y las mismas reglas, y no
 * un arreglo en la plantilla de uno de ellos.
 *
 * `overflow-x: clip` es la última defensa, como en `.sol-wrap`: `clip` y no
 * `hidden` porque `hidden` crea un contenedor de desplazamiento y en iOS eso
 * rompe la barra fija de abajo. */
.pub-form { width: 100%; max-width: 520px; min-width: 0; overflow-x: clip; }
.pub-form select,
.pub-form textarea,
.pub-form input,
.pub-form .campo-nota,
.pub-form .casillas-locales {
  max-width: 100%; min-width: 0; box-sizing: border-box;
}
/* Fecha y fichero: en iOS el control nativo tiene ancho propio y se salta el
   `width: 100%` si conserva su apariencia. `display: block` y `width` AQUÍ, no
   heredados, porque ese ancho mínimo gana a la regla genérica de
   `.field-input`. El `select` conserva su apariencia a propósito: sin ella
   pierde la flecha y deja de parecer un desplegable. */
.pub-form input[type="date"].field-input,
.pub-form input[type="file"].field-input {
  -webkit-appearance: none; appearance: none;
  display: block; width: 100%;
}
.pub-form input[type="date"].field-input::-webkit-date-and-time-value {
  text-align: left; min-width: 0;
}
/* Y nada dentro del formulario puede empujarlo: un enlace largo pegado en la
   nota de ayuda hace lo mismo que un control ancho. */
.pub-form > *,
.pub-form > .pub-que > *,
.pub-form > .pub-quien > * { min-width: 0; max-width: 100%; }
.pub-form .campo-nota { overflow-wrap: anywhere; }

/* El lápiz y la papelera, al lado de Publicar.
 *
 * Cuadrados y del alto del botón para que los tres se lean como una misma
 * barra. En papel y sin relleno: publicar es lo que se viene a hacer y es el
 * único que pesa; estos dos son de servicio y no compiten por la mirada.
 *
 * El lado no es decorativo: por debajo del mínimo un dedo falla, y aquí fallar
 * significa borrar algo cuando querías editarlo. Nacieron con 38 px, que no es
 * ni una cosa ni la otra: ahora miden lo mismo de alto que el botón que tienen
 * al lado, que es justo lo que decía el párrafo de arriba y había dejado de
 * cumplirse el día que `.btn` subió a 44. */
.com-accion {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--toque-min); height: var(--toque-min);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-fg-secondary);
  cursor: pointer;
  transition: background var(--duration-base) var(--ease-out),
              color var(--duration-base) var(--ease-out),
              border-color var(--duration-base) var(--ease-out);
}
.com-accion:hover { background: var(--color-surface-muted); color: var(--color-fg); }
.com-accion .icon { width: 16px; height: 16px; }

/* La papelera solo se pone roja al apuntarla. En rojo desde el principio,
 * gritaría más que Publicar en una lista de veinte filas. */
.com-accion-borrar:hover {
  color: var(--color-danger);
  border-color: var(--color-danger);
  background: var(--color-danger-soft);
}
/* El borrador se ve que no está en la calle. */
.com-borrador { opacity: 0.62; }
.com-borrador .com-fila-cuerpo h2 { font-weight: 500; }

@media (max-width: 640px) {
  .com-fila { flex-direction: column; gap: 10px; }
  .com-fila-acciones { width: 100%; }
  /* En el móvil, Publicar se estira y los dos iconos se quedan de su tamaño:
     si se repartieran el ancho a partes iguales, la papelera sería tan grande
     como el botón de publicar. */
  .com-fila-acciones form:first-child { flex: 1; }
  .com-fila-acciones .btn { width: 100%; }
  .com-fila-acciones form:has(.com-accion) { flex: none; }
}

/* Un permiso que el rol ya concede. Atenuado, no escondido: si la cuenta deja
   de ser administradora, lo que esté marcado vuelve a contar — y esconderlo
   daría a entender que se ha perdido. */
.permiso-incluido { opacity: 0.45; }
.permiso-incluido input { cursor: help; }

/* Las casillas de permisos: el alto lo pone la hoja, no el `style=` de la
   plantilla, que solo dice cómo se colocan en fila. */
.permiso { min-height: var(--toque-min); }

/* Las fotos del alta. El `input` de verdad se esconde y se pulsa su etiqueta:
   el control nativo de ficheros es feísimo en móvil y dice «Seleccionar
   archivo», que no invita a hacer una foto. */
/* `.fichero-oculto` es el mismo truco con nombre neutro, para los de fuera del
   alta: lo usa el adjunto de la respuesta de la ficha. */
.sol-fotos-input,
.fichero-oculto {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  overflow: hidden;
}
.sol-fotos-boton {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  min-height: 48px;
  padding: 12px 16px;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  font-size: 14px;
  font-weight: 500;
  color: var(--color-fg-secondary);
  cursor: pointer;
}
.sol-fotos-boton:active { background: var(--color-surface-muted); }
.sol-fotos-boton .icon { width: 18px; height: 18px; }
/* Con el teclado: el input está escondido, así que el foco se ve en la etiqueta. */
.sol-fotos-input:focus-visible + .sol-fotos-boton,
.fichero-oculto:focus-visible + .btn {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
.sol-fotos-previa {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
}
.sol-fotos-previa img {
  width: 74px; height: 74px;
  object-fit: cover;
  border-radius: var(--radius-md, 8px);
  border: 1px solid var(--color-border);
}
.sol-fotos-aviso {
  width: 100%;
  margin: 2px 0 0;
  font-size: 12px;
  color: var(--color-danger-fg);
}

/* Los locales, ahora pulsables: cada uno filtra la lista de abajo.
   Es el foco del gerente, que lleva varios y no piensa en «lo mío» sino en
   «en cuál tengo que meterme». */
.est-local {
  display: block;
  text-decoration: none;
  color: inherit;
  cursor: pointer;
}
.est-local:active { background: var(--color-surface-muted); }
.est-local.elegido {
  border-color: var(--borde-control);
  box-shadow: inset 4px 0 0 var(--primario);
}
.est-filtro {
  margin: 12px 0 0;
  font-size: 14px;
  color: var(--color-fg-secondary);
}
.est-filtro a { color: var(--color-accent); }

/* Los tipos de publicación. Cada uno con su color, y todos con su etiqueta al
   lado: el color solo no distingue nada para quien no ve bien los colores, y
   cinco tonos son demasiados para memorizarlos. */
.com-tipo {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px 2px 6px;
  border-radius: 4px;
  background: var(--color-surface-muted);
  color: var(--color-fg-secondary);
  font-size: 12px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.com-tipo svg { width: 12px; height: 12px; }
.com-tipo.peq { font-size: 12px; margin-left: 6px; vertical-align: middle; }
.com-tipo-aviso     { background: var(--ambar-suave); color: var(--ambar-texto); }
.com-tipo-campana   { background: var(--brand-50); color: var(--brand-700); }
.com-tipo-objetivo  { background: var(--brand-50); color: var(--brand-600); }
html[data-theme="dark"] .com-tipo-campana,
html[data-theme="dark"] .com-tipo-objetivo { color: var(--color-fg-secondary); }
.com-tipo-formacion { background: var(--color-surface-muted); }

/* Lo que espera algo de quien lee. Se distingue de «importante» a propósito:
   importante es que lo leas; esto es que respondas. */
.com-pendiente { background: var(--aviso); color: var(--texto-sobre-aviso); }

/* Fijado. En gris a propósito: no es una alarma, es una chincheta. El ámbar
   está cogido por «importante» y por «confirmar», que sí piden algo de quien
   lee; si fijar gritara igual, acabarían gritando los tres y no se oiría
   ninguno. */
.com-fijado {
  background: var(--color-surface-muted);
  color: var(--color-fg-secondary);
}
/* Y el botón de la lista de quien publica, encendido cuando ya está fijado:
   es el único que alterna, así que tiene que decir en qué estado está. */
.com-accion-fijado { color: var(--ambar-texto); }

.com-etiquetas { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }

/* Confirmar la lectura. */
.com-confirmar {
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--color-border);
}
.com-pide { margin: 0 0 12px; font-size: 14px; color: var(--color-fg-secondary); }
.com-confirmado {
  display: flex; align-items: center; gap: 8px;
  margin: 0; font-size: 14px; color: var(--color-fg-secondary);
}
.com-confirmado svg { width: 17px; height: 17px; color: var(--color-success); }

/* A quién llega. Plegado, porque casi siempre basta con el número. */
.com-audiencia { margin-top: 6px; }
.com-audiencia > summary {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--color-fg-secondary); cursor: pointer;
}
.com-audiencia > summary .icon { width: 13px; height: 13px; }
.com-nadie { color: var(--color-danger-fg); font-weight: 500; }
.com-lista-gente {
  margin: 8px 0 0; padding-left: 18px;
  font-size: 12px; line-height: 1.6; color: var(--color-fg-secondary);
}
/* La cuenta detrás del nombre: está para desempatar dos Marías, no para
   leerse. Por eso va más pequeña y más apagada que el nombre. */
.com-usuario {
  font-size: var(--text-xs);
  color: var(--color-fg-tertiary);
}
.com-faltan {
  display: flex; align-items: flex-start; gap: 6px;
  margin: 10px 0 0; padding: 8px 10px;
  border-radius: var(--radius-md, 8px);
  background: var(--ambar-suave); color: var(--ambar-texto);
  font-size: 12px; line-height: 1.5;
}
.com-faltan .icon { width: 13px; height: 13px; flex: none; margin-top: 2px; }

/* ── Adjuntos ──────────────────────────────────────────────────────────────
   Dos formas porque son dos lecturas distintas: una imagen se MIRA y tiene que
   estar a la vista sin tocar nada; un PDF se ABRE, y hasta entonces lo único
   que hace falta saber es qué es y cuánto pesa. Todo con tokens, así que la
   pizarra del modo noche lo recoge sin una sola regla aparte. */
.adj-imagenes {
  display: flex; flex-direction: column; gap: 12px;
  margin: 22px 0 0;
}
/* El vídeo tutorial (2026-10-08): a lo ancho del texto y sin pasarse de alto,
   como una imagen, con su nombre y su peso debajo para quien prefiera
   bajarlo. Fondo oscuro mientras carga: es lo que se espera de un vídeo. */
.adj-videos { display: flex; flex-direction: column; gap: 14px; margin: 22px 0 0; }
.adj-video { margin: 0; }
.adj-video video {
  display: block;
  width: 100%;
  max-height: 460px;
  border-radius: var(--radius-md, 8px);
  background: #000;
}
.adj-pie {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: 6px; font-size: 14px; color: var(--color-fg-secondary);
}
.adj-pie a {
  display: inline-flex; align-items: center; min-height: var(--toque-min);
  color: var(--color-accent); overflow-wrap: anywhere;
}
.adj-imagenes img {
  display: block;
  width: 100%;
  /* Contenida: una foto de móvil en vertical ocupa tres pantallas y empuja
     fuera todo lo que venga detrás. Tocar la abre entera. */
  max-height: 420px;
  object-fit: contain;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  background: var(--color-surface-muted);
}

.adj-lista { list-style: none; margin: 18px 0 0; padding: 0; }
/* Sin la raya de separación: ahora cada adjunto lleva su propio marco (ver
   `.adj-nombre`) y las dos cosas juntas se leen como una tabla. */
.adj-fila {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 0;
}
/* El adjunto se descarga pulsándolo, así que tiene que PARECER que se pulsa:
   antes era una línea de texto de 17 px con un clip delante, indistinguible
   del nombre del fichero escrito en el cuerpo del comunicado. Ahora es un
   enlace-botón con marco, con su icono y con los 44 px de alto. */
.adj-nombre {
  display: flex; align-items: center; gap: 9px;
  flex: 1; min-width: 0;
  min-height: var(--toque-min);
  padding: 8px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg-elevated);
  color: var(--color-fg);
  font-size: 14px;
  text-decoration: none;
  transition: border-color var(--duration-fast), color var(--duration-fast);
}
.adj-nombre:hover { color: var(--color-accent); border-color: var(--color-accent); }
.adj-nombre svg { width: 17px; height: 17px; flex: none; color: var(--color-fg-tertiary); }
/* El nombre se recorta, el peso NO: es justo el dato que decide si abrirlo
   ahora o esperar a estar en el wifi del local. */
.adj-nombre > span:first-of-type {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.adj-peso { flex: none; color: var(--color-fg-tertiary); font-size: 12px; }
/* Cuánto pesa el correo y qué se queda fuera, encima de la lista del editor. */
.adj-correo {
  display: flex; gap: 8px; align-items: flex-start;
  margin: 0 0 12px; padding: 10px 12px;
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
  background: var(--color-surface-muted);
  font-size: 14px; line-height: 1.5; color: var(--color-fg-secondary);
}
.adj-correo .icon { flex: none; width: 16px; height: 16px; margin-top: 2px; }
.adj-documentos { margin-top: 20px; }
.adj-entrada { padding: 8px; font-size: 14px; }

/* El clip de la tarjeta: que lleva algo dentro, no qué. Va dentro de
   `.com-cola`, que es quien empuja a la derecha. */
.com-clip {
  display: inline-flex; align-items: center;
  color: var(--color-fg-tertiary);
}
.com-clip svg { width: 14px; height: 14px; }

/* A cuánta gente alcanza un grupo. Va arriba, junto al nombre: es el dato que
   decide si mandarle algo o no. */
.grupo-alcance {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 10px 0 0;
  padding: 7px 11px;
  border-radius: var(--radius-md, 8px);
  background: var(--color-surface-muted);
  font-size: 12px;
  color: var(--color-fg-secondary);
}
.grupo-alcance .icon { width: 14px; height: 14px; flex: none; }


/* ── Hoy: la portada como puerta de todas las herramientas (2026-09-18) ────── */
.hoy-persona {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--space-3); flex-wrap: wrap; margin-bottom: var(--space-5);
}
.hoy-persona > * { min-width: 0; }
.hoy-estado {
  margin: 0; padding: 6px 12px; border-radius: var(--radius-pill);
  background: var(--color-surface); border: 1px solid var(--color-border);
  font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-fg-muted);
  white-space: nowrap;
}

.hoy-pendientes { display: flex; flex-direction: column; gap: var(--space-2); }
.hoy-pendiente {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-4); text-decoration: none;
  background: var(--color-surface-strong); border: 1px solid var(--color-border);
  border-left: 4px solid var(--aviso); border-radius: var(--radius-lg);
  color: var(--color-fg); min-height: 56px;
}
/* Todo lo de aquí espera de ti: borde ocre (guía). Lo urgente, en rojo. */
.hoy-pendiente.urgencia-0 { border-left-color: var(--color-danger); }
.hoy-pendiente > .icon { width: 20px; height: 20px; flex-shrink: 0; color: var(--color-fg-muted); }
.hoy-pendiente .texto { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.hoy-pendiente .texto strong { font-size: var(--text-base); font-weight: var(--weight-semibold); overflow-wrap: anywhere; }
.hoy-pendiente .texto small { font-size: var(--text-sm); color: var(--color-fg-tertiary); overflow-wrap: anywhere; }
.hoy-pendiente .flecha { width: 16px; height: 16px; flex-shrink: 0; color: var(--color-fg-tertiary); }
.hoy-pendiente:hover { border-color: var(--color-accent); }

.hoy-accesos {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-3);
}
.hoy-acceso {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-2);
  padding: var(--space-4); text-decoration: none; min-height: 88px;
  background: var(--color-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-lg); color: var(--color-fg);
  font-size: var(--text-sm); font-weight: var(--weight-semibold);
}
.hoy-acceso .icon { width: 22px; height: 22px; color: var(--color-accent); }
.hoy-acceso:hover { border-color: var(--color-accent); background: var(--color-surface-strong); }
@media (min-width: 768px) {
  .hoy-accesos { grid-template-columns: repeat(4, 1fr); }
}


/* ── Atrás, arriba a la izquierda, en toda pantalla interior ───────────────── */
.volver-arriba {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 44px; margin-bottom: var(--space-3); padding-right: var(--space-3);
  font-size: var(--text-base); font-weight: var(--weight-semibold);
  color: var(--color-fg); text-decoration: none;
}
.volver-arriba .icon { width: 20px; height: 20px; color: var(--color-accent); }
.volver-arriba:hover { color: var(--color-accent); }

/* ═══ Zonas de toque en el teléfono ════════════════════════════════════════
 *
 * Lo que en el ordenador se apunta con el ratón —el menú lateral, los chips—
 * en el móvil se busca con el pulgar, muchas veces de pie y con una mano. Aquí
 * suben del mínimo del ratón (`--toque-raton`) al del dedo (`--toque-min`).
 *
 * Los `input`, los `select` y los `.btn` NO están en este bloque a propósito:
 * ya llevan los 44 px en las dos pantallas, porque un formulario se rellena
 * con prisa se use lo que se use.
 *
 * Va al final del fichero para que gane a las reglas de arriba sin tener que
 * repetir selectores más específicos.
 */
@media (max-width: 768px) {
  .chip { min-height: var(--toque-min); }
  /* El menú lateral del móvil es un cajón que se toca: aquí sí, los 44. */
  .nav-item { min-height: var(--toque-min); }
  /* La cabecera del grupo «Esperando» es una etiqueta, no un botón, y se pulsa
     igual: es lo que despliega lo que está en el tejado del local. */
  .grupo-cabecera { min-height: var(--toque-min); }
}

/* ── Consultas sobre un comunicado (fase 2a) ───────────────────────────────
 *
 * Dos pantallas con el mismo hilo: el local ve el SUYO debajo del comunicado y
 * quien contesta los ve TODOS en `/comunicados/<id>/consultas`. Las clases son
 * las mismas a propósito — un hilo tiene que leerse igual en los dos sitios, o
 * la conversación parece otra según quién la mire.
 *
 * Todo con tokens: el modo noche lo recoge sin una sola regla aparte. Y todo
 * con `min-width: 0` y `overflow-wrap`, que es la lección ya pagada en
 * `.pub-form`: un texto pegado sin espacios —una URL larga en una duda— estira
 * el bloque más que el teléfono y arrastra la pantalla de lado. */
.con-bloque {
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--color-border);
  min-width: 0;
  overflow-x: clip;   /* `clip` y no `hidden`: ver `.pub-form`. */
}
.con-titulo {
  display: flex; align-items: center; gap: 8px;
  margin: 0 0 14px;
  font-size: 16px; font-weight: 500; color: var(--color-fg);
}
.con-titulo .icon { width: 17px; height: 17px; flex: none; }

.con-hilo { list-style: none; margin: 0 0 14px; padding: 0; }
/* El mensaje. Los dos lados llevan el mismo marco y se distinguen por el
 * fondo y por de qué lado está la raya: en una columna de 390 px, las burbujas
 * a izquierda y derecha dejan la mitad del ancho sin usar y parten las frases
 * en tres palabras por línea. */
.con-msg {
  margin: 0 0 10px;
  padding: 10px 12px;
  border-radius: var(--radius-md, 8px);
  border-left: 3px solid var(--color-border);
  background: var(--color-surface-muted);
  min-width: 0;
}
.con-msg-equipo { border-left-color: var(--color-accent, var(--color-fg-secondary)); }
.con-quien {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px;
  margin: 0 0 4px;
  font-size: 12px; font-weight: 500; color: var(--color-fg-secondary);
}
.con-cuando { font-weight: 400; font-size: var(--text-xs); color: var(--color-fg-tertiary); }
.con-texto {
  /* Texto plano, como el cuerpo del comunicado: los saltos se respetan y no
     hay una sola etiqueta que sanear. */
  white-space: pre-line;
  font-size: 14.5px; line-height: 1.6; color: var(--color-fg);
  overflow-wrap: anywhere;
}

.con-estado, .con-nota, .con-vacio {
  margin: 0 0 12px;
  font-size: 14px; line-height: 1.55; color: var(--color-fg-secondary);
}
/* El badge y la frase que lo acompaña, en la misma línea mientras quepan. */
.con-estado { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

.con-form { display: block; min-width: 0; max-width: 100%; }
.con-form textarea.field-input {
  display: block; width: 100%; max-width: 100%; min-width: 0;
  box-sizing: border-box;
  margin-bottom: 10px;
}
/* El botón llega a 44 px por `.btn`; lo que se añade aquí es que en el móvil
 * ocupe la línea entera. Un botón de enviar a media línea, con el pulgar
 * derecho y el teléfono en la mano, se falla. */
.con-enviar, .con-acciones .btn { width: 100%; }
@media (min-width: 560px) {
  .con-enviar, .con-acciones .btn { width: auto; }
}
.con-acciones { display: flex; flex-wrap: wrap; gap: 8px; }

/* La tarjeta de un hilo en la pantalla de quien contesta. Todas se ven igual:
 * un hilo contestado no se apaga ni se esconde, porque releer qué se contestó
 * es medio motivo de que esto se guarde. */
.con-tarjeta { margin-bottom: 14px; min-width: 0; overflow-x: clip; }
.con-de {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin: 0 0 12px;
  font-size: 16px; font-weight: 500; color: var(--color-fg);
}
.con-de .icon { width: 17px; height: 17px; flex: none; }

/* El enlace a las consultas desde la lista de quien publica. */
.com-consultas { margin: 6px 0 0; font-size: 12px; }
.com-consultas a {
  display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px;
  /* 44 px de alto con el texto pequeño que lleva: es un enlace que se toca en
     el móvil, no una nota al pie. */
  min-height: var(--toque-min);
  color: var(--color-fg-secondary); text-decoration: none;
}
.com-consultas a:hover { text-decoration: underline; }
.com-consultas .icon { width: 14px; height: 14px; flex: none; }

/* ── Encuestas de Comunicados (2026-11-06) ─────────────────────────────────
   En la ficha, debajo del texto y antes de las dudas. Las estrellas son las
   de la valoración de una incidencia (44 px para el dedo, al revés en el HTML
   y `row-reverse` en pantalla); las opciones, filas enteras de 44 px que se
   tocan en cualquier parte. Todo con `min-width: 0`: una opción larga no
   puede estirar la ficha más que el teléfono. */
.enc-bloque .com-marca { margin-left: auto; }
.enc-form { display: grid; gap: 14px; min-width: 0; max-width: 100%; }
.enc-pregunta, .enc-editor-pregunta { border: 0; padding: 0; margin: 0; min-width: 0; }
.enc-enunciado {
  padding: 0; margin: 0 0 8px;
  font-size: 14.5px; font-weight: 500; line-height: 1.45; color: var(--color-fg);
  overflow-wrap: anywhere;
}
.enc-opcional { font-weight: 400; color: var(--color-fg-tertiary); }
.enc-oculto {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}
.enc-estrellas { display: flex; flex-direction: row-reverse; justify-content: flex-end; gap: 2px; }
.enc-estrellas input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.enc-estrellas label {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; cursor: pointer;
  font-size: 32px; line-height: 1;
  color: transparent; -webkit-text-stroke: 1.5px var(--borde-control, var(--color-border));
}
.enc-estrellas input:checked ~ label,
.enc-estrellas label:hover, .enc-estrellas label:hover ~ label { color: var(--color-fg); -webkit-text-stroke: 0; }
.enc-estrellas input:focus-visible + label { outline: 2px solid var(--color-accent, currentColor); border-radius: var(--radius-md, 8px); }
.enc-opciones { display: grid; gap: 6px; min-width: 0; }
.enc-opcion {
  display: flex; align-items: center; gap: 10px;
  min-height: var(--toque-min, 44px); padding: 6px 12px;
  border: 1px solid var(--color-border); border-radius: var(--radius-md, 8px);
  font-size: 14.5px; color: var(--color-fg); cursor: pointer; min-width: 0;
}
.enc-opcion span { min-width: 0; overflow-wrap: anywhere; }
.enc-opcion input { width: 20px; height: 20px; flex: none; margin: 0; }
.enc-form textarea.field-input { display: block; width: 100%; max-width: 100%; box-sizing: border-box; }
.enc-ultima { display: flex; align-items: center; gap: 6px; }
.enc-ultima .icon { width: 16px; height: 16px; flex: none; color: var(--color-success); }
.enc-leida { margin: 0; display: grid; gap: 10px; }
.enc-leida dt { font-size: 13px; color: var(--color-fg-secondary); }
.enc-leida dd { margin: 2px 0 0; font-size: 14.5px; color: var(--color-fg); white-space: pre-line; overflow-wrap: anywhere; }

/* El editor de preguntas: cada pregunta, una tarjeta interior. */
.enc-explica { margin-bottom: 14px; }
.enc-lista { display: grid; gap: 14px; min-width: 0; }
.enc-editor-pregunta {
  display: grid; gap: 10px;
  padding: 12px; border: 1px solid var(--color-border); border-radius: var(--radius-md, 8px);
}
.enc-editor-pregunta .field-label { display: grid; gap: 4px; min-width: 0; }
.enc-editor-pregunta .field-input { width: 100%; max-width: 100%; box-sizing: border-box; }
.enc-dos { display: grid; gap: 10px; min-width: 0; }
.enc-dos > * { min-width: 0; }
/* `2fr 1fr` y no `minmax(0, …)`: `test_cola_escritorio` cuenta las rejillas
   con `minmax(0, 1fr)` de este fichero como si fueran de la cola. El
   desbordamiento lo impide el `min-width: 0` de los hijos. */
@media (min-width: 560px) { .enc-dos { grid-template-columns: 2fr 1fr; } }
.enc-opciones-campo[hidden], .enc-quitar[hidden], #enc-otra[hidden] { display: none; }
.enc-quitar { justify-self: start; min-height: var(--toque-min, 44px); }
.enc-errores { margin-bottom: 14px; border-left: 3px solid var(--color-danger, #c0392b); }
.enc-errores ul { margin: 6px 0 0; padding-left: 18px; }
.enc-leidas { margin: 0 0 12px; padding-left: 20px; display: grid; gap: 8px; }
.enc-leidas li { overflow-wrap: anywhere; }
.enc-leidas .campo-nota { display: block; }

/* Los resultados: una tarjeta por pregunta, barras como las de valoraciones. */
.enc-resultado { margin-bottom: 12px; min-width: 0; overflow-x: clip; }
.enc-r-titulo { margin: 0 0 4px; font-size: 16px; font-weight: 500; color: var(--color-fg); overflow-wrap: anywhere; }
.enc-reparto { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 8px; }
.enc-reparto li { display: grid; grid-template-columns: 7em 1fr 6.5em; align-items: center; gap: 10px; }
.enc-reparto li > * { min-width: 0; }
.enc-reparto-et { color: var(--color-fg-secondary); overflow-wrap: anywhere; font-size: 14px; }
.enc-reparto-n { white-space: nowrap; font-variant-numeric: tabular-nums; text-align: right; font-size: 14px; }
.enc-reparto-n small { color: var(--color-fg-tertiary); }
.enc-barra { height: 10px; border-radius: 5px; background: var(--color-surface-muted); overflow: hidden; }
.enc-barra span { display: block; height: 100%; background: var(--color-warning, var(--color-accent)); }
.enc-textos { list-style: none; margin: 10px 0 0; padding: 0; }
.enc-textos li { padding: 10px 0; border-bottom: 1px solid var(--color-border); min-width: 0; }
.enc-textos li:last-child { border-bottom: 0; }
.enc-texto-local {
  display: flex; align-items: center; gap: 6px; margin: 0 0 4px;
  font-size: 12px; font-weight: 500; color: var(--color-fg-secondary);
}
.enc-texto-local .icon { width: 14px; height: 14px; flex: none; }

/* ── Quién lo ha leído (fase 2b) ────────────────────────────────────────────
   Una lista de hasta setenta nombres en un móvil de 390: lo que la hace
   legible es el agrupado por local y que cada línea quepa entera. El nombre
   manda, la cuenta y la fecha son de apoyo y van más pequeñas. */
.lec-cabecera { margin-bottom: 14px; min-width: 0; overflow-x: clip; }
.lec-estado { margin: 0 0 8px; font-size: 14px; color: var(--color-fg-secondary); }
.lec-resumen { margin: 0; font-size: 14.5px; line-height: 1.7; color: var(--color-fg); }
.lec-recordar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin-top: 14px; padding-top: 14px;
  border-top: 1px solid var(--color-border);
}
/* Ancho completo en el móvil: es el botón al que se ha venido. */
.lec-recordar .btn { width: 100%; }
@media (min-width: 560px) { .lec-recordar .btn { width: auto; } }
/* Exportar es secundario: va debajo del resumen y no compite con «Recordar». */
.lec-exportar { margin: 12px 0 0; }

.lec-grupo { margin-bottom: 12px; min-width: 0; overflow-x: clip; }
.lec-local {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin: 0 0 10px;
  font-size: 16px; font-weight: 500; color: var(--color-fg);
}
.lec-local .icon { width: 17px; height: 17px; flex: none; }
.lec-titulo-lista {
  margin: 10px 0 4px;
  font-size: 12px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--color-fg-tertiary);
}
.lec-gente { margin: 0; padding: 0; list-style: none; }
.lec-gente li {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px;
  /* 44 px por línea: aquí se toca para llamar por teléfono, y una lista de
     veinte nombres a 28 px de alto es imposible de recorrer con el pulgar. */
  min-height: var(--toque-min);
  padding: 6px 0;
  border-bottom: 1px solid var(--color-border);
  font-size: 14px; line-height: 1.5;
}
.lec-gente li:last-child { border-bottom: 0; }
.lec-gente .icon { width: 14px; height: 14px; flex: none; align-self: center; }
/* El nombre se lleva el espacio que sobra y la fecha cae debajo cuando no
   cabe: en 390 px, un nombre largo y una fecha en la misma línea partían el
   nombre por la mitad. */
.lec-nombre { flex: 1 1 auto; min-width: 0; color: var(--color-fg); }
.lec-cuando { font-size: var(--text-xs); color: var(--color-fg-tertiary); }
.lec-falta > .icon { color: var(--ambar-texto, var(--color-fg-tertiary)); }
.lec-ok > .icon { color: var(--color-success); }

/* El enlace a esta pantalla desde la lista de quien publica. Inline-flex para
   poder darle los 44 px de alto sin romper la línea de estado donde vive. */
.lec-enlace {
  display: inline-flex; align-items: center;
  min-height: var(--toque-min);
  color: var(--color-fg-secondary);
}


/* El aviso que sustituye a la caja de responder cuando quien mira la ficha no
   la trabaja (un supervisor). No es un error ni una advertencia: es decirle
   dónde está el límite de su rol, así que va en tono neutro y no en rojo. */
.solo-mira {
  margin: var(--space-4) 0 0;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-muted);
  color: var(--color-fg-muted);
  font-size: var(--text-sm);
  line-height: 1.5;
}


/* El original de un comentario que llegó por correo, recortado por defecto
   (firma y aviso legal fuera, #7915). Discreto: está para quien lo necesite. */
.correo-completo { margin-top: var(--space-2); font-size: var(--text-sm); }
.correo-completo summary { cursor: pointer; color: var(--color-fg-muted); min-height: 32px; display: flex; align-items: center; }
.correo-completo .texto, .correo-completo .bubble { white-space: pre-wrap; color: var(--color-fg-muted); }

/* ── El correo de un comunicado, antes de que salga ──────────────────────────
 * Dos botones en el editor y un diálogo con el correo dentro de un `iframe`.
 * En «Móvil» el marco mide 390 px, que es el ancho al que se lee en los locales;
 * en «Ancho», lo que dé la pantalla. */
.correo-vista { margin-top: 14px; }
.correo-vista-botones { display: flex; flex-wrap: wrap; gap: 8px; }
.correo-vista-botones .btn { min-height: var(--toque-min); }
.correo-vista-estado:empty { display: none; }
.correo-vista-estado { margin-top: 6px; }
.correo-vista-error { color: var(--color-danger); }
.correo-dialogo {
  width: min(880px, 96vw); max-width: 96vw; max-height: 94vh;
  padding: 14px; box-sizing: border-box;
  border: 1px solid var(--color-border); border-radius: var(--radius-lg);
  background: var(--color-surface); color: var(--color-fg);
}
.correo-dialogo::backdrop { background: rgb(var(--sombra-tinta) / 0.45); }
.correo-dialogo-cabeza { display: flex; align-items: flex-start; gap: 10px; }
.correo-dialogo-asunto { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.correo-dialogo-asunto .campo-nota { display: block; margin: 0 0 2px; }
.correo-cerrar { min-width: var(--toque-min); min-height: var(--toque-min); }
.correo-anchos { display: flex; gap: 6px; margin: 10px 0; }
/* `display: flex` le gana a `[hidden]`: sin esto, la elección de versión
   saldría también sin listas de fuera. */
.correo-versiones[hidden], .correo-externo-nota[hidden], .com-previa-externo[hidden] { display: none; }
.correo-ancho {
  min-height: var(--toque-min); padding: 0 14px;
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
  background: var(--color-surface); color: var(--color-fg-secondary);
  font: inherit; font-size: var(--text-sm); cursor: pointer;
}
.correo-ancho.activo {
  background: var(--color-accent-soft); color: var(--color-fg);
  border-color: var(--color-border-strong); font-weight: var(--weight-semibold);
}
.correo-marco {
  display: flex; justify-content: center;
  background: var(--color-surface-muted); border-radius: var(--radius-md);
  overflow: auto;
}
.correo-iframe {
  width: 100%; height: 66vh; border: 0; background: var(--crema);
}
.correo-ancho-movil .correo-iframe { width: 390px; max-width: 100%; }

/* ── El formato del cuerpo en el editor ────────────────────────────────────
 * La barra escribe marcas en el texto y la vista previa la pinta el servidor
 * con la misma conversión que la ficha (Victor, 2026-10-06). Botones de 44:
 * se usa con el pulgar, en la barra de un local. */
.fmt-barra {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin: 0 0 6px;
}
.fmt-boton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 46 y no 44 justos: según dónde caiga la barra, el navegador la coloca en
     medio píxel y el botón mide 43,99 — por debajo del mínimo en la regla. */
  width: calc(var(--toque-min) + 2px);
  height: calc(var(--toque-min) + 2px);
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-fg);
  cursor: pointer;
}
.fmt-boton svg { width: 18px; height: 18px; }
.fmt-boton:hover { background: var(--color-surface-muted); }
.fmt-boton:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 1px; }
/* El selector de color del resaltado: cuatro muestras de 44 debajo del
   botón. Va pegado a él (y no en una caja aparte como el enlace) porque es
   una elección de un toque, no un campo que rellenar. */
.fmt-resaltar { position: relative; display: inline-flex; }
.fmt-colores {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 20;
  display: flex;
  gap: 6px;
  padding: 6px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .14);
}
.fmt-colores[hidden] { display: none; }
.fmt-color {
  width: calc(var(--toque-min) + 2px);
  height: calc(var(--toque-min) + 2px);
  padding: 0;
  border: 1px solid rgba(0, 0, 0, .18);
  border-radius: var(--radius-md);
  cursor: pointer;
}
.fmt-color:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.fmt-pide-enlace {
  margin: 0 0 8px;
  padding: 10px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-muted);
}
.fmt-pide-enlace[hidden] { display: none; }
.fmt-pide-fila { display: flex; flex-wrap: wrap; gap: 6px; }
.fmt-pide-fila .field-input { flex: 1 1 200px; min-width: 0; min-height: var(--toque-min); }
.fmt-pide-fila .btn { min-height: var(--toque-min); }
.fmt-pide-error { color: var(--color-danger); }
.fmt-pide-error:empty { display: none; }
.fmt-ayuda { margin: 6px 0 0; font-size: 14px; }
.fmt-ayuda summary {
  display: flex;
  align-items: center;
  min-height: var(--toque-min);
  cursor: pointer;
  color: var(--color-fg-secondary);
  font-weight: 500;
}
.fmt-ejemplos { margin: 0 0 6px; padding-left: 18px; line-height: 1.7; color: var(--color-fg-secondary); }
.fmt-ejemplos code, .fmt-ayuda code {
  font-family: var(--font-mono);
  font-size: 12px;
  padding: 1px 5px;
  border-radius: var(--radius-xs);
  background: var(--color-surface-muted);
  color: var(--color-fg);
}
.fmt-previa {
  margin-top: 10px;
  padding: 14px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}
.fmt-previa-titulo {
  margin: 0 0 8px;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--color-fg-tertiary);
}
.fmt-previa-vacia { margin: 0; font-size: 14px; color: var(--color-fg-tertiary); }
.fmt-previa-vacia[hidden] { display: none; }
.fmt-previa-cuerpo:empty { display: none; }
.fmt-previa-estado:empty { display: none; }

/* ── El escritorio ancho (≥ 1200 px) ─────────────────────────────────────────
 * Victor, 2026-10-06: en su pantalla de 1920 el formulario de un comunicado
 * ocupaba 520 px y el resto estaba en blanco. No se estira todo: el lado se
 * usa para algo que hace falta mirar MIENTRAS se trabaja en lo de la izquierda
 * (la vista previa del comunicado, los datos y las acciones de una ficha).
 *
 * Por qué 1200: por debajo la barra lateral (256) y los márgenes (72) dejan
 * menos de 870 px, y dos columnas útiles no caben. Y por encima de 1180 queda
 * fuera el iPad apaisado (1180 el Air, 1024 los demás): la tableta y el móvil
 * no cambian nada, y por eso todo esto vive en una sola consulta y lo de
 * fuera solo esconde el panel nuevo. El mismo número está en
 * `comunicado-previa.js` (no pide nada si el panel no se ve). */
.com-previa { display: none; }
.com-editor-tarjeta { max-width: 620px; }
.com-ficha-datos { display: none; }

@media (min-width: 1200px) {
  /* ── Editor de comunicados: formulario | vista previa pegajosa ── */
  .com-editor {
    display: grid;
    grid-template-columns: minmax(0, 680px) minmax(360px, 1fr);
    gap: 28px;
    align-items: start;
  }
  .com-editor-form { min-width: 0; }
  .com-editor-tarjeta { max-width: none; }
  /* El alta vive en un `<details>` con su `max-width` de 440 (`.ayuda-nueva
     .ayuda-form`): aquí la columna ya pone el ancho. */
  .com-editor .pub-form.ayuda-form { max-width: none; }
  /* Lo que el panel sustituye: la vista previa bajo el campo y los botones
     del diálogo del correo. En el móvil siguen siendo los únicos. */
  .com-editor .pub-form .fmt-previa,
  .com-editor .pub-form .correo-vista { display: none; }

  .com-previa {
    position: sticky;
    top: 16px;
    display: flex;
    flex-direction: column;
    height: calc(100dvh - 32px);
    min-width: 0;
    padding: 14px;
    box-sizing: border-box;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    background: var(--color-surface);
  }
  .com-previa-cabeza {
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px;
    margin-bottom: 12px;
  }
  .com-previa-cabeza .fmt-previa-titulo { margin: 0; flex: 1 0 100%; }
  .com-previa-pestanas, .com-previa-anchos { display: flex; gap: 6px; }
  .com-previa-anchos { margin-left: auto; }
  .com-previa-pestanas .correo-ancho { display: inline-flex; align-items: center; gap: 6px; }
  .com-previa-pestanas .icon { width: 15px; height: 15px; }

  .com-previa-cuerpo { flex: 1; min-height: 0; display: flex; flex-direction: column; }
  .com-previa-hoja { flex: 1; min-height: 0; display: flex; flex-direction: column; }
  .com-previa-hoja[hidden] { display: none; }

  /* «En la app»: la ficha del comunicado, a 390 (el teléfono del local) o al
     ancho que tiene la ficha en el escritorio. */
  .com-previa-hoja[data-previa-hoja="app"] {
    overflow: auto;
    padding: 18px 16px;
    border-radius: var(--radius-md);
    background: var(--color-surface-muted);
  }
  .com-previa-app {
    width: 100%; max-width: 390px; margin: 0 auto; box-sizing: border-box;
    padding: 18px 16px;
    border-radius: var(--radius-md);
    background: var(--color-bg);
  }
  .com-previa-ancha .com-previa-app { max-width: 640px; }
  .com-previa-etiquetas { display: flex; flex-wrap: wrap; gap: 6px; }
  .com-previa-etiquetas:empty { display: none; }
  .com-previa-h1 {
    margin: 10px 0 12px;
    font-family: var(--font-display);
    font-size: 25px; font-weight: 400; line-height: 1.22; letter-spacing: 0;
    color: var(--color-fg);
    overflow-wrap: anywhere;
  }
  .com-previa-texto:empty { display: none; }
  .com-previa-vacia[hidden] { display: none; }
  .com-previa-error:empty { display: none; }

  /* «Por correo»: el marco ocupa lo que quede de alto. */
  .com-previa-asunto { margin: 0 0 8px; overflow-wrap: anywhere; }
  .com-previa-asunto .campo-nota { display: block; margin: 0 0 2px; }
  .com-previa-marco { flex: 1; min-height: 320px; }
  .com-previa-marco .correo-iframe { height: auto; width: 390px; max-width: 100%; }
  .com-previa-ancha .com-previa-marco .correo-iframe { width: 100%; }

  .com-previa-pie { margin-top: 12px; }

  /* ── La ficha de un comunicado: texto | datos, Enterado, documentos, dudas ──
     Rejilla sobre los hijos de siempre y no una columna que los envuelva:
     el «Enterado» va entre el texto y las imágenes en el móvil, y meterlo en
     un envoltorio lo habría cambiado de sitio también allí. El texto ocupa
     las tres primeras filas, así que las imágenes van justo debajo de él y la
     columna de la derecha empieza arriba aunque el texto sea largo. */
  /* El conjunto se centra en el área de contenido: con el bloque pegado a la
     izquierda, a 1920 quedaba un tercio vacío a la derecha (revisión del
     PR #21). El texto se queda en ancho de lectura; lo que sobra lo toma la
     columna de al lado hasta 480 y, después, se reparte a los dos lados. */
  .com-detalle.com-ficha {
    max-width: calc(680px + 56px + 480px);
    margin: 0 auto;
    display: grid;
    grid-template-columns: minmax(0, 680px) minmax(300px, 480px);
    grid-template-rows: auto auto 1fr auto auto;
    column-gap: 56px;
    justify-content: center;
    align-items: start;
  }
  .com-ficha > .com-ficha-texto { grid-column: 1; grid-row: 1 / span 3; min-width: 0; }
  /* El vídeo, debajo del texto y antes de las imágenes: es lo que explica. */
  .com-ficha > .adj-videos { grid-column: 1; grid-row: 4; }
  .com-ficha > .adj-imagenes { grid-column: 1; grid-row: 5; }
  .com-ficha > .com-ficha-datos { grid-column: 2; grid-row: 1; }
  .com-ficha > .com-confirmar { grid-column: 2; grid-row: 2; }
  .com-ficha > .com-ficha-lado { grid-column: 2; grid-row: 3 / span 3; min-width: 0; }
  /* La firma pasa a ser la tarjeta de datos de la derecha. */
  .com-ficha .com-firma { display: none; }
  .com-ficha-texto h1 { margin-bottom: 14px; }
  .com-ficha-datos {
    display: grid; gap: 10px;
    margin: 0;
    padding: 14px 16px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    background: var(--color-surface);
  }
  .com-ficha-datos div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
  .com-ficha-datos dt {
    font-size: var(--text-xs); text-transform: uppercase;
    letter-spacing: var(--tracking-wide); color: var(--color-fg-muted);
    font-weight: var(--weight-semibold);
  }
  .com-ficha-datos dd { margin: 0; color: var(--color-fg); overflow-wrap: anywhere; }
  /* En la columna de al lado, cada bloque arranca sin la raya de «sección
     siguiente» que lleva en el móvil: allí separa del texto; aquí ya lo
     separa la columna. */
  .com-ficha > .com-confirmar {
    margin-top: 16px; padding: 14px 16px;
    border: 1px solid var(--color-border); border-radius: var(--radius-lg);
    background: var(--color-surface);
  }
  /* ── Ayuda: las fichas rellenan la fila ──
     Con `auto-fill`, a 1920 caben cinco columnas de ~310 px y con tres
     teléfonos se quedaban dos VACÍAS: el tercio en blanco de la derecha que
     vio Victor. `auto-fit` pliega las columnas sin ficha y las que hay se
     reparten la fila. Para que dos o una no queden absurdamente anchas, la
     rejilla se recorta cuando el bloque tiene menos de tres (~520 por ficha,
     lo que ya mide un bloque de tres a 1920). Las ocultas por el buscador
     (`hidden`) no cuentan como ficha, y la fila se recompone sola. */
  .ayuda-fichas { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
  .ayuda-fichas:not(:has(> .ayuda-ficha:not([hidden]) ~ .ayuda-ficha:not([hidden]) ~ .ayuda-ficha:not([hidden]))) {
    max-width: calc(2 * 520px + 12px);
  }
  .ayuda-fichas:not(:has(> .ayuda-ficha:not([hidden]) ~ .ayuda-ficha:not([hidden]))) {
    max-width: 520px;
  }
  /* Una ficha de teléfono abierta para editar se queda con la fila: si la
     rejilla se recortó a 520 por tener pocas fichas, la suelta. */
  .ayuda-fichas:has(.ayuda-editar[open] [data-es-tel]) { max-width: none; }
  /* El formulario de un teléfono en dos columnas: lo de la ficha a la
     izquierda y los números, que es lo largo, a la derecha. Los números en
     dos columnas también, que a 1440 una sola caja de 900 px es un páramo. */
  .ayuda-form-rejilla[data-es-tel] {
    display: grid;
    grid-template-columns: minmax(260px, 340px) 1fr;
    gap: 0 24px;
    align-items: start;
  }
  .ayuda-form-rejilla[data-es-tel] > * { min-width: 0; }
  .ayuda-nueva .ayuda-form:has([data-es-tel]) { max-width: 1100px; }
  .tel-nums { grid-template-columns: repeat(auto-fill, minmax(380px, 1fr)); align-items: start; }

  /* ── Quién lo ha leído y Consultas: tarjetas en columnas ──
     A 1920 cada local era una franja de 1600 px con el nombre a la izquierda
     y la hora a 1300 px de él. En columnas (el orden baja por la primera y
     sigue en la siguiente, así que los pendientes siguen siendo lo primero)
     la ronda de llamadas cabe en una pantalla, y cada fila se lee de un
     vistazo. Con `columns` y no rejilla: las tarjetas miden lo que miden y
     una rejilla dejaría huecos al lado de la más larga. */
  .lec-grupos { columns: 400px; column-gap: 14px; }
  .con-tarjetas { columns: 520px; column-gap: 16px; }
  .lec-grupos > .lec-grupo,
  .con-tarjetas > .con-tarjeta { break-inside: avoid; }

  .com-ficha-lado > :first-child { margin-top: 16px; }
  .com-ficha-lado .con-bloque { margin-top: 16px; }
}

/* ── Archivar, histórico y quién responde (anexo A-008, 2026-10-06) ─────────
 * Archivado en gris, como el fijado: no pide nada a quien lee, solo cuenta
 * que esto ya no está en Hoy. El ámbar sigue siendo de lo que espera algo. */
.com-archivado,
.com-caducado {
  background: var(--color-surface-muted);
  color: var(--color-fg-secondary);
}
.com-responde { margin-top: -4px; }
.con-responde {
  margin: 6px 0 0;
  font-size: 14px; line-height: 1.5; color: var(--color-fg-secondary);
}
.con-original { margin-bottom: 16px; padding: 12px 16px; }
.con-original > summary {
  display: flex; align-items: center;
  min-height: var(--toque-min);
  cursor: pointer;
  font-weight: 500; color: var(--color-fg);
}
.con-original .com-cuerpo { margin-top: 8px; }

/* El enlace de Hoy y el botón de la lista de quien publica: a la vista y del
   tamaño de un dedo, que es lo que no era «Y 3 más de antes». */
.hoy-historico {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: var(--toque-min);
  margin-top: 4px;
  font-size: 14px; font-weight: 500;
  color: var(--color-accent);
  text-decoration: none;
}
.hoy-historico .icon { width: 16px; height: 16px; }

/* El buscador: en el móvil, uno debajo de otro y el botón a lo ancho; desde
   la tableta, en una fila. Flex y no rejilla a propósito: los tests de la
   cola cuentan las rejillas con columna elástica de toda la hoja, y esta no
   es de la cola. */
.hist-buscar {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 14px;
}
.hist-buscar .field { min-width: 0; margin: 0; }
.hist-buscar .field-input { width: 100%; box-sizing: border-box; }
.hist-boton { width: 100%; }
@media (min-width: 641px) {
  .hist-buscar { flex-direction: row; align-items: flex-end; }
  .hist-q { flex: 1 1 auto; }
  .hist-tipo { flex: 0 0 200px; }
  .hist-boton { width: auto; flex: none; }
}
.hist-cuenta { margin: 0 0 14px; font-size: 14px; color: var(--color-fg-tertiary); }
.hist-quitar {
  display: inline-flex; align-items: center; min-height: var(--toque-min);
  color: var(--color-accent); font-weight: 500;
}

/* La tarjeta entera se toca para abrirla: el enlace del título se estira por
   encima con un `::after`, y lo que hay que pulsar aparte (las acciones de
   quien publica) va por delante con su propio `z-index`. */
.hist-tarjeta h2 { padding-right: 0; }
/* El título mide lo que un dedo aunque sea de una línea: el `::after` ya
   hace tocable la tarjeta entera, pero el enlace en sí es lo que lee un lector
   de pantalla y lo que mide la herramienta de capturas. */
.hist-abrir {
  display: flex; align-items: center; min-height: var(--toque-min);
  color: inherit; text-decoration: none; overflow-wrap: anywhere;
}
.hist-abrir::after { content: ''; position: absolute; inset: 0; border-radius: inherit; }
.hist-tarjeta:active { background: var(--color-surface-muted); }
.hist-pie { margin: 8px 0 0; font-size: 14px; color: var(--color-fg-secondary); }
.hist-acciones {
  position: relative; z-index: 1;
  display: flex; flex-wrap: wrap; gap: 8px;
  margin-top: 12px;
}
.hist-acciones form { margin: 0; }
@media (max-width: 640px) {
  .hist-acciones > * { flex: 1 1 100%; }
  .hist-acciones .btn { width: 100%; }
}
.hist-paginas {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  gap: 10px; margin: 18px 0 8px;
}
.hist-paginas > :last-child { justify-self: end; }
.hist-pagina { font-family: var(--font-mono); font-size: 12px; color: var(--color-fg-tertiary); }

@media (min-width: 1200px) {
  /* Como Consultas y Quién lo ha leído: tarjetas en columnas en vez de una
     franja de 1600 px por comunicado. */
  .hist-buscar { max-width: 980px; }
  .hist-lista { columns: 460px; column-gap: 14px; }
  .hist-lista > .hist-tarjeta { break-inside: avoid; display: inline-block; width: 100%; box-sizing: border-box; }
}
/* «Ver las consultas» en la ficha: un enlace dentro de una frase, y aun así
   es lo único que se viene a pulsar en ese bloque. */
.con-nota a {
  display: inline-flex; align-items: center; min-height: var(--toque-min);
  color: var(--color-accent); font-weight: 500;
}

/* ── Duplicar y plantillas de comunicados (Victor, 2026-10-06) ───────────────
 * El selector «Empezar desde una plantilla» va encima del alta; «Guardar como
 * plantilla» dentro del formulario, debajo de la vista del correo. Lo que se
 * pulsa mide lo que un dedo (`--toque-min`), también cada plantilla de la
 * lista: en el móvil se eligen con el pulgar. */
.com-cabeza-acciones { display: flex; flex-wrap: wrap; gap: 8px; }
@media (max-width: 640px) {
  .com-cabeza-acciones { width: 100%; }
  .com-cabeza-acciones .btn { flex: 1 1 auto; justify-content: center; }
  /* Con «Duplicar» son cinco iconos y un botón: que bajen de línea antes que
     salirse de la pantalla. */
  .com-fila-acciones { flex-wrap: wrap; }
}

.plant-elegir, .plant-guardar, .plant-archivadas {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  margin: 0 0 14px;
}
.plant-elegir > summary, .plant-guardar > summary, .plant-archivadas > summary {
  display: flex; align-items: center; gap: 8px;
  min-height: var(--toque-min);
  padding: 0 14px;
  cursor: pointer;
  font-weight: 500; font-size: 14px;
  color: var(--color-fg);
}
.plant-elegir > summary .icon, .plant-guardar > summary .icon,
.plant-archivadas > summary .icon { width: 16px; height: 16px; flex: none; }
.plant-cuantas {
  margin-left: auto;
  font-family: var(--font-mono); font-size: 12px; font-weight: 500;
  color: var(--color-fg-tertiary);
}
.plant-elegir-cuerpo, .plant-guardar-cuerpo { padding: 0 14px 14px; min-width: 0; }
.plant-elegir-cuerpo .field-input, .plant-guardar-cuerpo .field-input {
  width: 100%; box-sizing: border-box;
}
.plant-opciones {
  list-style: none; margin: 10px 0 6px; padding: 0;
  max-height: 340px; overflow-y: auto;
  border-top: 1px solid var(--color-border);
}
.plant-opciones li { border-bottom: 1px solid var(--color-border); }
.plant-opcion {
  display: flex; flex-direction: column; justify-content: center;
  min-height: var(--toque-min);
  padding: 8px 4px;
  color: inherit; text-decoration: none;
}
.plant-opcion:hover, .plant-opcion:focus-visible { background: var(--color-surface-muted); }
.plant-opcion-nombre { font-weight: 500; color: var(--color-accent); overflow-wrap: anywhere; }
.plant-opcion-detalle {
  font-size: 14px; color: var(--color-fg-secondary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.plant-opcion-detalle:empty { display: none; }
.plant-elegir-cuerpo .campo-nota a, .plant-sin a {
  display: inline-flex; align-items: center; min-height: var(--toque-min);
  color: var(--color-accent); font-weight: 500;
}
.plant-sin { margin: 0 0 12px; }
[data-plant-item][hidden], .plant-nada[hidden] { display: none; }

.plant-guardar { margin: 14px 0 0; background: var(--color-surface-muted); }
.plant-guardar-cuerpo .field-label { margin-top: 4px; }
.plant-guardar-publico, .plant-con-publico, .dup-adjunto {
  min-height: var(--toque-min); margin: 2px 0;
}
.plant-guardar-cuerpo .btn { margin-top: 6px; }
.plant-estado:empty { display: none; }
.plant-estado { margin-top: 8px; }

/* Lo que se recortó del público al rellenar: se dice arriba, antes del
   formulario, porque es lo que puede hacer que algo no le llegue a alguien. */
.plant-avisos {
  display: flex; gap: 10px; align-items: flex-start;
  margin: 0 0 14px; padding: 10px 14px;
  border-radius: var(--radius-md);
  background: var(--color-warning-soft); color: var(--color-warning-fg);
  font-size: 14px;
}
.plant-avisos .icon { width: 16px; height: 16px; flex: none; margin-top: 2px; }
.plant-avisos p { margin: 0; }
.campo-nota-aviso { color: var(--color-warning-fg); }

.dup-adjuntos { border: 0; padding: 0; margin: 0 0 12px; min-width: 0; }
/* «Enviar también por correo a»: cada lista es una fila de 44 que se marca
   con el pulgar, con su número de direcciones a la derecha. */
.pub-listas { border: 0; padding: 0; margin: 0 0 12px; min-width: 0; }
.pub-lista {
  min-height: var(--toque-min); margin: 2px 0;
  font-size: 14px; color: var(--color-fg);
}
.pub-lista input { width: 18px; height: 18px; flex: none; }
.pub-lista-nombre { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.dup-adjunto { font-size: 14px; color: var(--color-fg); }
.dup-adjunto .icon { width: 15px; height: 15px; flex: none; color: var(--color-fg-tertiary); }
.dup-adjunto-nombre { min-width: 0; overflow-wrap: anywhere; }

.com-duplicar { margin-top: 14px; }

/* La pantalla de plantillas: tarjetas como el histórico, sin enlace estirado
   (aquí lo que se hace con una plantilla son tres botones, no abrirla). */
.plant-buscar { max-width: 520px; margin-bottom: 8px; }
.plant-buscar .field-input { width: 100%; box-sizing: border-box; }
.plant-nombre { margin: 8px 0 2px; font-size: 16px; overflow-wrap: anywhere; }
.plant-titulo { margin: 0 0 4px; font-size: 14px; color: var(--color-fg-secondary); overflow-wrap: anywhere; }
.plant-tarjeta:active { background: var(--color-surface); }
.plant-archivadas { margin-top: 18px; }
.plant-archivadas-lista { list-style: none; margin: 0; padding: 0 14px 10px; }
.plant-archivada {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 8px; padding: 8px 0; border-top: 1px solid var(--color-border);
}
.plant-archivada form { margin: 0; }
.plant-archivada-nombre { min-width: 0; overflow-wrap: anywhere; font-weight: 500; }
.plant-archivada-nombre .com-usuario { display: block; font-weight: 400; }
@media (max-width: 640px) {
  .plant-nueva { width: 100%; justify-content: center; }
  .plant-archivada form, .plant-archivada .btn { width: 100%; }
}
@media (min-width: 1200px) {
  /* Como el histórico: tarjetas en columnas en vez de franjas de 1600 px. */
  .plant-lista { columns: 420px; column-gap: 14px; }
  .plant-lista > .plant-tarjeta {
    break-inside: avoid; display: inline-block; width: 100%; box-sizing: border-box;
  }
  .plant-archivadas { max-width: 860px; }
  /* El selector del alta, al ancho de la columna del formulario. */
  .com-editor-form > .plant-elegir, .com-editor-form > .plant-sin { max-width: 680px; }
}
/* `display: inline-block` de las columnas le ganaría al `[hidden]` del
   buscador (REGLAS: «display: flex le gana a [hidden]»). */
.plant-lista > .plant-tarjeta[hidden] { display: none; }

/* ── Alta y edición de cuentas (/admin, 2026-10-07) ─────────────────────────
   Un formulario por pasos —quién es, qué hace, hasta dónde llega, qué ve
   primero, qué más puede hacer— y un resumen que dice qué va a pasar al
   guardar. En el móvil, todo en una columna con el resumen justo encima del
   botón; desde 1200 px, el resumen se queda fijo en una columna al lado.
   Va al final de la hoja y con `1fr` y no `minmax(0, 1fr)`: los tests de la
   cola cuentan las rejillas elásticas de esta hoja y el primer `@media` de
   escritorio; el `min-width: 0` de cada hijo hace lo mismo que el `minmax`. */
.cuenta-plegable {
  display: flex; align-items: center; gap: 8px;
  min-height: var(--toque-min);
  cursor: pointer; font-weight: var(--weight-semibold);
}
.cuenta-plegable .icon { width: 16px; height: 16px; flex-shrink: 0; }
.cuenta-ayuda, .cuenta-alta { margin-bottom: 18px; }
.cuenta-ayuda-lista { margin: 10px 0 0; display: grid; gap: 4px 16px; }
.cuenta-ayuda-lista dt { font-weight: var(--weight-semibold); font-size: var(--text-sm); color: var(--color-fg); margin-top: 8px; }
.cuenta-ayuda-lista dd { margin: 0; font-size: var(--text-sm); line-height: 1.5; color: var(--color-fg-secondary); }
.cuenta-ayuda-sub { margin: 14px 0 4px; font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-fg); }
.cuenta-ayuda-ejemplos { margin: 0; padding-left: 18px; font-size: var(--text-sm); line-height: 1.55; color: var(--color-fg-secondary); }

.cuenta-form { display: flex; flex-direction: column; gap: 18px; margin-top: 14px; min-width: 0; }
.cuenta-pasos { display: flex; flex-direction: column; gap: 18px; min-width: 0; }
.cuenta-paso {
  margin: 0; min-width: 0;
  padding: 14px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}
/* `display` en el fieldset le ganaría a `[hidden]` (REGLAS). */
.cuenta-paso[hidden], .cuenta-paso-oculto[hidden], .cuenta-aviso[hidden],
.cuenta-sin-ambito[hidden], .cuenta-resumen-texto[hidden],
.cuenta-resumen-titulo[hidden], .cuenta-paso-intro[hidden],
.cuenta-activa[hidden] { display: none; }
.cuenta-paso-titulo {
  display: flex; align-items: center; gap: 8px;
  padding: 0 4px;
  font-size: var(--text-md); font-weight: var(--weight-semibold); color: var(--color-fg);
}
.cuenta-paso-num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; flex-shrink: 0;
  border-radius: var(--radius-pill);
  background: var(--color-accent-soft); color: var(--color-accent);
  font-size: var(--text-xs); font-weight: var(--weight-bold);
}
.cuenta-paso-intro { margin: 2px 0 12px; font-size: var(--text-sm); line-height: 1.5; color: var(--color-fg-secondary); }
.cuenta-paso-oculto {
  display: flex; align-items: center; gap: 8px;
  margin: 0; padding: 0 14px;
  font-size: var(--text-sm); color: var(--color-fg-tertiary);
}
.cuenta-campos { display: grid; grid-template-columns: 1fr; gap: 12px; }
.cuenta-campos + .cuenta-campos { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--color-border); }
.cuenta-campos .field { min-width: 0; }
.cuenta-campos .campo-nota { font-size: var(--text-xs); }
.cuenta-fijo { margin: 0; min-height: var(--toque-min); display: flex; align-items: center; color: var(--color-fg); overflow-wrap: anywhere; }
.cuenta-activa {
  display: flex; align-items: center; gap: 9px;
  min-height: var(--toque-min); cursor: pointer;
  font-size: var(--text-base); color: var(--color-fg);
}
.cuenta-activa input { width: 20px; height: 20px; accent-color: var(--color-accent); }

/* Las tarjetas del rol: radios de verdad, la tarjeta entera es la etiqueta. */
.cuenta-roles { display: grid; grid-template-columns: 1fr; gap: 8px; }
.cuenta-rol {
  display: flex; align-items: flex-start; gap: 10px;
  min-height: var(--toque-min); box-sizing: border-box;
  min-width: 0;
  padding: 10px 12px;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-bg-elevated);
  cursor: pointer;
}
.cuenta-rol input { width: 20px; height: 20px; flex-shrink: 0; margin: 1px 0 0; accent-color: var(--color-accent); }
.cuenta-rol-texto { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cuenta-rol-texto strong { font-size: var(--text-base); color: var(--color-fg); }
.cuenta-rol-texto small { font-size: var(--text-sm); line-height: 1.4; color: var(--color-fg-secondary); }
.cuenta-rol:has(input:checked) { border-color: var(--color-accent); background: var(--color-accent-soft); }
.cuenta-rol:has(input:focus-visible) { outline: 2px solid var(--color-accent); outline-offset: 2px; }

.cuenta-sin-ambito, .cuenta-aviso {
  margin: 0 0 12px; padding: 9px 12px;
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  font-size: var(--text-sm); line-height: 1.5;
}
.cuenta-sin-ambito { border-left: 3px solid var(--color-border-strong); background: var(--color-surface-muted); color: var(--color-fg-secondary); }
.cuenta-aviso { border-left: 3px solid var(--color-warning); background: var(--color-warning-soft); color: var(--color-warning-fg); }
.cuenta-paso .filter-grid { margin-top: 0; }

/* El bloque de Selección (Nexus) dentro de «Qué más puede hacer». */
.cuenta-seleccion[hidden] { display: none; }
.cuenta-seleccion .btn { min-height: var(--toque-min); margin: 4px 0 6px; }
.cuenta-seleccion-estado {
  margin: 4px 0; padding: 7px 10px;
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  font-size: var(--text-sm); line-height: 1.45; overflow-wrap: anywhere;
  border-left: 3px solid var(--color-border-strong); background: var(--color-surface-muted);
  color: var(--color-fg-secondary);
}
.cuenta-seleccion-ok { border-left-color: var(--color-success, var(--color-accent)); color: var(--color-fg); }
.cuenta-seleccion-aviso { border-left-color: var(--color-warning); background: var(--color-warning-soft); color: var(--color-warning-fg); }

/* Los permisos, por grupos con su explicación. */
.permiso-grupo {
  margin: 0 0 10px; padding: 8px 12px 6px; min-width: 0;
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
}
.permiso-grupo:last-child { margin-bottom: 0; }
.permiso-grupo legend { padding: 0 4px; font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-fg); }
.permiso-grupo-explica { margin: 0 0 4px; font-size: var(--text-xs); line-height: 1.45; color: var(--color-fg-tertiary); }
.permiso-grupo-aviso { border-color: var(--color-warning); }
.permiso-grupo-alerta {
  display: flex; align-items: center; gap: 6px;
  margin: 0 0 4px; font-size: var(--text-xs); font-weight: var(--weight-semibold);
  color: var(--color-warning-fg);
}
.permiso-grupo-alerta .icon { width: 14px; height: 14px; flex-shrink: 0; }
.permiso-lista { display: flex; flex-wrap: wrap; gap: 0 16px; }
.permiso-lista .permiso {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: var(--text-sm); color: var(--color-fg-secondary); cursor: pointer;
}
.permiso-lista .permiso input { width: 18px; height: 18px; flex-shrink: 0; accent-color: var(--color-accent); }
/* Lo que da el rol (2026-10-09): marcado y bloqueado, con su etiqueta. */
.permiso-del-rol { color: var(--color-fg); cursor: default; }
.permiso-lista .permiso-del-rol input { cursor: not-allowed; }
.permiso-del-rol-marca {
  display: inline-block; padding: 1px 6px; border-radius: var(--radius-sm);
  font-size: var(--text-xs); font-weight: var(--weight-semibold); white-space: nowrap;
  background: var(--color-accent-soft); color: var(--color-accent);
}
.permiso-del-rol-marca[hidden] { display: none; }

/* /admin/roles: un paquete por rol, con su confirmación antes de guardar. */
.roles-explica p { margin: 0 0 6px; line-height: 1.5; }
.roles-explica p:last-child { margin-bottom: 0; }
.rol-editor { display: flex; flex-direction: column; gap: 10px; padding-top: 10px; }
.rol-editor-botones .btn, .rol-confirmar-botones .btn { min-height: var(--toque-min); }
.rol-confirmar {
  display: flex; flex-direction: column; gap: 6px; margin-top: 10px; padding: 12px 14px;
  border: 1px solid var(--color-warning); border-radius: var(--radius-md);
  background: var(--color-warning-soft); color: var(--color-warning-fg);
}
.rol-confirmar-titulo { display: flex; align-items: center; gap: 8px; margin: 0; font-weight: var(--weight-semibold); }
.rol-confirmar-titulo .icon { width: 16px; height: 16px; flex-shrink: 0; }
.rol-confirmar-linea { margin: 0; overflow-wrap: anywhere; }
.rol-confirmar-botones { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.rol-admin .grupo-resumen { cursor: default; }
.roles-historial { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 6px; font-size: var(--text-sm); overflow-wrap: anywhere; }
.roles-historial-cuando { color: var(--color-fg-tertiary); margin-right: 6px; }

/* El resumen y los botones. */
.cuenta-resumen {
  display: flex; flex-direction: column; gap: 10px; min-width: 0;
  padding: 14px;
  border: 1px solid var(--color-accent-soft);
  border-radius: var(--radius-lg);
  background: var(--color-accent-softer);
}
.cuenta-resumen-titulo { margin: 0; font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-fg); }
.cuenta-resumen-texto { margin: 0; font-size: var(--text-base); line-height: 1.55; color: var(--color-fg); overflow-wrap: anywhere; }
.cuenta-botones { display: flex; flex-direction: column; gap: 8px; }
.cuenta-botones .btn { width: 100%; min-height: var(--toque-min); justify-content: center; }
.cuenta-botones .campo-nota { margin: -2px 0 4px; overflow-wrap: anywhere; }

/* La lista de cuentas: una fila por persona, que abre su ficha. */
.cuentas { display: flex; flex-direction: column; }
.cuenta-fila { border-top: 1px solid var(--color-border-soft); }
.cuenta-fila:first-child { border-top: 0; }
.cuenta-fila-cabeza {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px;
  min-height: var(--toque-min); padding: 8px 4px;
  cursor: pointer; list-style: none;
}
.cuenta-fila-cabeza::-webkit-details-marker { display: none; }
/* Desde el 2026-10-10 la cabecera es un enlace a la ficha y no el resumen
   de un desplegable: sin esto saldría azul y subrayada entera. */
a.cuenta-fila-cabeza { color: inherit; text-decoration: none; }
.cuenta-fila-quien { display: flex; flex-direction: column; min-width: 0; flex: 1 1 160px; }
.cuenta-fila-quien strong { color: var(--color-fg); overflow-wrap: anywhere; }
.cuenta-fila-usuario { font-size: var(--text-xs); color: var(--color-fg-tertiary); overflow-wrap: anywhere; }
.cuenta-fila-datos { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.cuenta-fila-login { font-size: var(--text-xs); color: var(--color-fg-tertiary); }
.cuenta-fila-editar { margin-left: auto; font-size: var(--text-sm); color: var(--color-accent); text-decoration: underline; }

@media (min-width: 640px) {
  .cuenta-campos { grid-template-columns: 1fr 1fr; }
  .cuenta-roles { grid-template-columns: 1fr 1fr; }
}

@media (min-width: 1200px) {
  .cuenta-form {
    display: grid;
    grid-template-columns: 1fr 340px;
    gap: 24px;
    align-items: start;
  }
  .cuenta-campos { grid-template-columns: 1fr 1fr 1fr; }
  .cuenta-roles { grid-template-columns: 1fr 1fr 1fr; }
  .cuenta-resumen { position: sticky; top: 16px; }
}

/* El ámbito de técnico y supervisor: los departamentos primero (son su cola) y
   los locales debajo, como opcionales (revisión del PR #35). Lo ordena la hoja
   con el `data-primero` que pone `roles.js`: el HTML no se reordena. */
.cuenta-ambito { display: flex; flex-direction: column; gap: 4px; }
.cuenta-ambito[data-primero="departamentos"] [data-ambito="departamentos"] { order: -1; margin-bottom: 12px; }
.cuenta-ambito-titulo {
  margin: 0 0 8px; padding-top: 10px;
  border-top: 1px solid var(--color-border);
  font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-fg);
}
.cuenta-ambito-titulo[hidden], .cuenta-ambito .campo-nota[hidden] { display: none; }
/* ═══ Oficina / Locales (contrato OFICINA, 2026-10-07) ═════════════════════
 *
 * La pastilla «Oficina» de la cola y de la ficha. Va en los tokens de INFO:
 * no es un aviso ni una alarma, solo dice de dónde viene, y así no se confunde
 * con «sin tipificar» (aviso) ni con «alta» (peligro). Los tokens ya están
 * definidos para el modo noche.
 */
.badge.badge-oficina {
  background: var(--color-info-soft);
  color: var(--color-info-fg);
}

/* El conmutador «Todas / Oficina / Locales» de la cola vivía aquí. Desde el
 * 2026-10-10 el origen es un filtro más del panel (ver «LA COLA NUEVA»). */

/* ── Grupos de locales plegables (/admin/grupos, 2026-10-07) ────────────────
   Cada grupo es un `<details>` cerrado: la cabecera dice nombre, cuántos
   locales y personas, quién lo usa y a cuántos llega; el editor sale al abrir.
   Victor: «aparece desplegado siempre y es complejo». */
.grupo-tarjeta { margin-bottom: 14px; min-width: 0; }
/* `.card` pone `display` y le ganaría al `[hidden]` del buscador (REGLAS). */
.grupo-tarjeta[hidden], .grupos-barra[hidden], .grupos-nada[hidden],
.casillas-filtro[hidden], .casillas-nada[hidden],
.casillas-legibles > label[hidden] { display: none; }
.grupo-resumen {
  display: flex; align-items: center; gap: 12px;
  min-height: var(--toque-min);
  cursor: pointer; list-style: none;
}
.grupo-resumen::-webkit-details-marker { display: none; }
.grupo-resumen-texto { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.grupo-nombre { font-weight: var(--weight-semibold); color: var(--color-fg); overflow-wrap: anywhere; }
.grupo-meta {
  display: flex; align-items: center; gap: 6px;
  font-size: var(--text-sm); color: var(--color-fg-secondary); overflow-wrap: anywhere;
}
.grupo-meta .icon { width: 13px; height: 13px; flex: none; }
.grupo-flecha {
  width: 18px; height: 18px; flex: none;
  color: var(--color-fg-tertiary);
  transition: transform var(--duration-fast);
}
.grupo-tarjeta[open] > .grupo-resumen .grupo-flecha { transform: rotate(180deg); }
.grupo-tarjeta[open] > .grupo-resumen {
  padding-bottom: 12px; margin-bottom: 14px;
  border-bottom: 1px solid var(--color-border);
}
.grupo-editor { min-width: 0; }

.grupos-barra {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin-bottom: 14px;
}
.grupos-barra .field-input { flex: 1 1 220px; min-width: 0; max-width: 360px; }
.grupos-barra-acciones { display: flex; gap: 8px; flex-wrap: wrap; }
.grupos-barra-acciones .btn { min-height: var(--toque-min); }
.grupos-nada, .casillas-nada { margin: 0 0 14px; font-size: var(--text-sm); color: var(--color-fg-secondary); }
.casillas-nada { margin: 8px 0 0; }

/* Las casillas legibles: el mismo `.casillas-locales` de la pantalla de
   usuarios, con un ancho mínimo de columna que no parte nombres y el texto en
   su propio bloque, que puede bajar de línea sin montarse en la columna de al
   lado. Las marcadas, resaltadas como la tarjeta de rol elegida en usuarios. */
.casillas-filtro { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.casillas-filtro .field-input { flex: 1 1 auto; min-width: 0; max-width: 320px; }
.casillas-cuenta { font-size: var(--text-sm); color: var(--color-fg-secondary); white-space: nowrap; }
.casillas-legibles {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 180px), 1fr));
  gap: 4px 10px;
  /* En el escritorio, sin caja con scroll propio: catorce filas caben y un
     scroll dentro de otro era la mitad del «es complejo». */
  max-height: none;
}
.casillas-legibles > label {
  min-width: 0;
  align-items: flex-start;
  padding: 8px 8px;
  border-radius: var(--radius-sm, 6px);
  line-height: 1.3;
}
.casillas-legibles > label > input { flex: none; margin: 2px 0 0; }
.casilla-texto { min-width: 0; overflow-wrap: anywhere; color: var(--color-fg); }
.casilla-texto .com-usuario { display: block; margin-top: 2px; }
.casillas-legibles > label:has(input:checked) { background: var(--color-accent-soft); }
.casillas-personas { grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr)); max-height: 300px; }
@media (max-width: 640px) {
  /* En el móvil setenta locales son una columna de metros: aquí sí se queda
     una caja con su scroll, y el buscador encima. */
  .casillas-legibles { max-height: 50vh; grid-template-columns: repeat(auto-fill, minmax(min(100%, 140px), 1fr)); }
  .casillas-personas { grid-template-columns: 1fr; }
}

/* ── Correos de los locales (/admin/correos-locales, 2026-10-07) ───────────
   Los plegables de /admin/grupos con las filas de /admin/aviso-seleccion: un
   correo por fila y sus dos casillas de uso a la derecha, que bajan debajo
   del correo cuando no caben (a 390 un correo largo no empuja nada fuera). */
.corloc-grupo[hidden] { display: none; }
.corloc-cuenta { font-weight: var(--weight-regular, 400); color: var(--color-fg-tertiary); }
.corloc-fila { flex-wrap: wrap; }
.corloc-correo { flex: 1 1 240px; min-width: 0; }
.corloc-usos { display: flex; gap: var(--space-3); flex-wrap: wrap; }
.corloc-uso {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: var(--toque-min); cursor: pointer;
  font-size: var(--text-sm); color: var(--color-fg);
}
.corloc-acciones { display: flex; gap: 8px; flex-wrap: wrap; }
.corloc-acciones [hidden] { display: none; }

/* ── «Ver como…» (2026-10-08) ────────────────────────────────────────────────
 * La franja va DENTRO del armazón y a todo lo ancho: en el escritorio ocupa una
 * fila de la rejilla y la barra lateral pega debajo de ella; en el móvil el
 * armazón es una columna fija, así que la franja es un hijo más que no se
 * desplaza nunca. Ámbar y no el verde de la casa: tiene que parecer otra cosa. */
.ver-como-franja {
  grid-column: 1 / -1;
  position: sticky; top: 0;
  z-index: var(--z-sidebar);
  display: flex; align-items: center; justify-content: center; gap: 12px;
  flex-wrap: wrap;
  min-height: var(--franja-alto, 52px);
  padding: 4px 16px;
  padding-top: max(4px, env(safe-area-inset-top));
  /* Un aviso de estado, no algo pendiente: el ocre es solo para lo segundo. */
  background: var(--color-warning-soft);
  color: var(--color-warning-fg);
  border-bottom: 2px solid var(--color-warning);
  font-size: var(--text-sm);
  line-height: 1.3;
  box-sizing: border-box;
}
.ver-como-franja .ver-como-texto { min-width: 0; overflow-wrap: anywhere; }
.ver-como-franja form { margin: 0; flex-shrink: 0; }
.ver-como-volver {
  min-height: var(--toque-min);
  padding: 0 16px;
  border: 0; border-radius: var(--radius-pill);
  background: var(--azul-noche); color: var(--crema);
  font: inherit; font-weight: var(--weight-semibold);
  cursor: pointer;
}
.ver-como-volver:hover { background: #0b1830; }
.app-shell.viendo-como { --franja-alto: 52px; }
.app-shell.viendo-como .app-sidebar {
  top: var(--franja-alto);
  height: calc(100dvh - var(--franja-alto));
}

/* El selector, en el pie de la barra lateral (en el móvil, detrás de «Más»). */
.ver-como { border-radius: var(--radius-md); }
.ver-como-abrir {
  list-style: none;
  display: flex; align-items: center; gap: 8px;
  min-height: var(--toque-min);
  padding: 0 10px;
  border-radius: var(--radius-md);
  cursor: pointer;
  font-size: var(--text-sm); font-weight: var(--weight-semibold);
  color: inherit;
}
.ver-como-abrir::-webkit-details-marker { display: none; }
.ver-como-abrir .icon { width: 16px; height: 16px; }
.ver-como-abrir:hover { background: hsl(0 0% 100% / 0.08); }
.ver-como-lista {
  margin: 4px 0 0;
  display: flex; flex-direction: column; gap: 2px;
  max-height: 40dvh; overflow-y: auto;
}
.ver-como-cuenta {
  display: flex; flex-direction: column; align-items: flex-start; justify-content: center;
  min-height: var(--toque-min);
  padding: 4px 10px;
  border: 0; border-radius: var(--radius-sm);
  background: transparent; color: inherit;
  font: inherit; text-align: left;
  cursor: pointer;
}
.ver-como-cuenta:hover { background: hsl(0 0% 100% / 0.08); }
.ver-como-cuenta[disabled] { cursor: default; background: hsl(0 0% 100% / 0.12); }
.ver-como-rol { font-size: var(--text-xs); opacity: 0.7; }
.ver-como-nombre { font-size: var(--text-sm); font-weight: var(--weight-semibold); }

@media (max-width: 768px) {
  .ver-como-franja { position: static; flex: none; padding-left: 12px; padding-right: 12px; }
  .ver-como-franja .ver-como-texto { flex: 1 1 180px; }
  /* La franja ya se come la zona segura de arriba; la barra no la repite. */
  .app-shell.viendo-como .mobile-topbar { padding-top: 10px; }
  .app-shell.viendo-como .app-sidebar { top: 0; height: auto; }
}


/* ═══ LA COLA NUEVA (Victor, 2026-10-10, sobre la maqueta) ══════════════════
 *
 * Buscar y «Filtros» en una fila; debajo, la pestaña de estado («Por hacer ·
 * En espera · Resueltas · Todas»); debajo, las pastillas de lo que filtra y no
 * es de tu vista. En el ordenador, todo en una fila y las pastillas debajo.
 * El panel de Filtros, una hoja desde abajo en el móvil con los dos botones
 * siempre a la vista. El porqué de cada cosa, en `inbox.html` y `mi_vista`. */

.fila-buscar { display: flex; gap: 8px; align-items: stretch; flex: 1 1 auto; min-width: 0; }
.fila-buscar .inbox-search { flex: 1 1 auto; min-width: 0; }
.btn-filtros { flex: none; position: relative; min-height: var(--toque-raton); white-space: nowrap; }
.btn-filtros .icon { flex: none; width: 16px; height: 16px; }
.filtros-num {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px; margin-left: 2px;
  border-radius: 999px; background: var(--color-accent); color: var(--color-fg-inverse);
  font-size: 12px; font-weight: var(--weight-bold); font-variant-numeric: tabular-nums;
}

.selector-estado { display: flex; }
.selector-estado button {
  justify-content: center; white-space: nowrap; padding-inline: 14px;
  min-height: var(--toque-raton);
}
.selector-estado .estado-cuenta {
  font-size: var(--text-xs); color: var(--color-fg-muted); font-variant-numeric: tabular-nums;
}
.selector-estado .estado-cuenta:empty { display: none; }
.selector-estado button.is-active .estado-cuenta { color: inherit; opacity: .8; }

.filtros-activos { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; flex-basis: 100%; order: 99; }
.filtros-activos .chip { padding-inline: 12px 10px; gap: 6px; }
.filtros-activos .chip .icon { width: 14px; height: 14px; opacity: .85; }
.volver-mi-vista {
  display: inline-flex; align-items: center; min-height: var(--toque-raton); padding: 0 6px;
  color: var(--color-accent); font-size: var(--text-sm); font-weight: var(--weight-semibold);
  text-decoration: underline; text-underline-offset: 3px; margin-left: 4px;
}

@media (min-width: 769px) {
  .cola-barra .toolbar-spacer { display: none; }
  .cola-barra .fila-buscar { flex: 1 1 240px; }
}

/* Por debajo de 1024, el selector de estado va ANTES que los cuatro contadores
   (revisión de Astra, aprobada por Victor el 2026-10-10): la primera decisión
   al entrar es QUÉ lista ver —«Por hacer», «En espera»…—, y los contadores son
   una herramienta secundaria que recorta esa lista. Con ellos arriba, lo
   primero que se tocaba era un filtro antes de saber qué se estaba filtrando.
   El selector vive dentro de la barra, así que sube la barra entera (buscar y
   Filtros encima, como en la maqueta aprobada, y las pastillas debajo). En el
   teléfono `.inbox-metrics` es `display: contents` y lo que se ordena es
   `.metrics-accion` (bloque «LA COLA EN UN TELÉFONO»). El escritorio, igual. */
@media (max-width: 1023px) {
  .inbox-controls > .inbox-toolbar { order: 1; }
  .inbox-controls > .inbox-metrics { order: 2; }
}

@media (max-width: 768px) {
  /* Tres filas: [buscar · Filtros], la pestaña a todo lo ancho, las pastillas. */
  .cola-barra .fila-buscar { width: 100%; }
  .btn-filtros { min-height: var(--toque-min); }
  .selector-estado { width: 100%; }
  .selector-estado button { flex: 1 1 0; min-height: var(--toque-min); padding-inline: 6px; }
  .filtros-activos .chip { min-height: var(--toque-min); }
  .volver-mi-vista { min-height: var(--toque-min); margin-left: auto; }
}

/* «Resueltas»: un punto más apagadas, que ya no son trabajo. */
[data-grupo="resueltas"] .ticket-row { opacity: .78; }
[data-grupo="resueltas"] .ticket-row .subj { color: var(--color-fg-secondary); }

/* ── El panel de Filtros ─────────────────────────────────────────────────── */
.hoja-filtros.saona-modal-backdrop { z-index: var(--z-modal); }
.panel-filtros.saona-modal {
  display: flex; flex-direction: column; padding: 0; overflow: hidden; max-width: 560px;
}
.panel-filtros .saona-modal-head { padding: 14px 16px 0; margin-bottom: 2px; }
.panel-filtros .saona-modal-head h2 { font-size: var(--text-lg); }
.panel-filtros .saona-modal-head .close-btn { width: var(--toque-min); height: var(--toque-min); }
.panel-filtros-icono { width: 20px; height: 20px; color: var(--color-accent); }
.panel-filtros-nota { margin: 0 16px 6px; font-size: var(--text-xs); color: var(--color-fg-tertiary); }
.panel-filtros-form { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
.panel-filtros-cuerpo {
  overflow-y: auto; overscroll-behavior: contain; padding: 4px 16px 12px;
  display: flex; flex-direction: column; gap: 14px; min-height: 0;
}
.hoja-sec h3 {
  margin: 0 0 6px; font-size: var(--text-xs); font-weight: var(--weight-semibold);
  text-transform: uppercase; letter-spacing: var(--tracking-wide); color: var(--color-fg-secondary);
  display: flex; align-items: baseline; gap: 6px;
}
.hoja-sec h3 small {
  text-transform: none; letter-spacing: 0; font-weight: var(--weight-regular); color: var(--color-fg-muted);
}
.hoja-sec .filter-search { margin-bottom: 6px; }
.hoja-pastillas { display: flex; flex-wrap: wrap; gap: 6px; }
.pastilla-filtro { min-height: var(--toque-min); padding-inline: 14px; font-size: var(--text-sm); }
/* La casilla de verdad sigue ahí (formulario, teclado, lector de pantalla);
   lo que se ve es la pastilla. */
.pastilla-filtro input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; pointer-events: none; }
.pastilla-filtro .pastilla-ok { display: none; width: 14px; height: 14px; }
.pastilla-filtro:has(input:checked) {
  background: var(--color-accent-soft); border-color: var(--color-accent);
  color: var(--color-accent); font-weight: var(--weight-semibold);
}
.pastilla-filtro:has(input:checked) .pastilla-ok { display: inline-block; }
.pastilla-filtro:has(input:focus-visible) { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.hoja-dos { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 8px; }
.hoja-dos .check-item { padding: 6px; font-size: var(--text-sm); min-height: var(--toque-min); }
.panel-filtros-pie {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px; flex: none;
  padding: 10px 16px max(12px, env(safe-area-inset-bottom));
  border-top: 1px solid var(--color-border); background: var(--color-bg-elevated);
}
.panel-filtros-pie .btn { min-height: var(--toque-min); justify-content: center; width: 100%; }

@media (max-width: 768px) {
  /* Una hoja desde abajo, por ENCIMA de la barra de navegación: el panel se
     cuelga del <body> al abrirse (`inbox.js`) y así ninguna caja del
     contenido lo deja por debajo. Antes la barra tapaba el «Guardar». */
  .hoja-filtros.saona-modal-backdrop { align-items: flex-end; padding: 0; }
  .panel-filtros.saona-modal {
    border-radius: var(--radius-2xl) var(--radius-2xl) 0 0; max-height: 88dvh; border-bottom: 0;
  }
}

/* ── Reabrir con motivo (2026-10-14) ─────────────────────────────────────────
   Un <dialog> nativo con la piel de `.saona-modal`: ventana en el ordenador y
   hoja desde abajo en el móvil, como el panel de Filtros. */
.reabrir-dialogo {
  border: 1px solid var(--color-border); border-radius: var(--radius-2xl);
  background: var(--color-bg-elevated); color: var(--color-fg);
  padding: 0; width: min(520px, calc(100vw - 32px)); max-height: 88dvh;
  box-shadow: var(--shadow-3);
}
.reabrir-dialogo::backdrop { background: rgb(var(--sombra-tinta) / 0.55); }
.reabrir-form { display: flex; flex-direction: column; gap: 8px; padding: 14px 16px max(14px, env(safe-area-inset-bottom)); }
.reabrir-cabeza { display: flex; align-items: center; gap: 10px; }
.reabrir-cabeza h2 { margin: 0; font-size: var(--text-lg); font-weight: var(--weight-bold); }
.reabrir-cabeza .close-btn {
  margin-left: auto; width: var(--toque-min); height: var(--toque-min);
  background: transparent; border: 0; border-radius: var(--radius-sm); cursor: pointer;
  color: var(--color-fg-tertiary); font-size: 22px; line-height: 1;
}
.reabrir-motivo { width: 100%; min-height: 110px; resize: vertical; font-family: inherit; }
.reabrir-nota { margin: 0; font-size: var(--text-sm); color: var(--color-fg-secondary); }
.reabrir-pie { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 4px; }
.reabrir-pie .btn { min-height: var(--toque-min); justify-content: center; width: 100%; }
.reabrir-acciones { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.reabrir-acciones .btn { min-height: var(--toque-min); }
.reabrir-linea div { overflow-wrap: anywhere; }
@media (max-width: 768px) {
  .reabrir-dialogo {
    margin: auto 0 0; width: 100vw; max-width: 100vw;
    border-radius: var(--radius-2xl) var(--radius-2xl) 0 0; border-bottom: 0;
  }
}
/* En la ficha del equipo, las líneas de reapertura van en el resumen, como
   «Tarea pedida por…» y con el mismo enlace. */
.ticket-summary .sum-reabierta { color: var(--color-fg); }
.ticket-summary .sum-reabierta .icon { color: var(--color-accent); }
.ticket-summary .sum-reabierta a { color: var(--color-accent); font-weight: var(--weight-semibold); }

/* «Hacer foto» y «Galería», uno al lado del otro (2026-10-20, Android). */
.sol-fotos-botones { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.sol-fotos-mini { position: relative; }
.sol-fotos-mini img { display: block; }
.sol-fotos-quitar {
  position: absolute; top: -8px; right: -8px;
  width: 28px; height: 28px; border-radius: 50%;
  border: 1px solid var(--color-border-strong); background: var(--color-surface);
  color: var(--color-fg); font-size: 18px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
/* El dedo no acierta en 28 px: la zona que se pulsa es de 44. */
.sol-fotos-quitar::after { content: ""; position: absolute; inset: -8px; }

/* ── Menciones con @ (2026-11-09, menciones.js) ──────────────────────────
   La lista va en el flujo, a lo ancho de la caja: a 390 px no se sale ni la
   tapa el teclado. Cada persona es un botón de 44 px. */
.menciones-lista {
  max-height: 220px;
  overflow-y: auto;
  margin: 6px 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg, 10px);
  background: var(--color-surface);
  box-sizing: border-box;
  width: 100%;
}
.menciones-lista[hidden] { display: none; }
.menciones-op {
  all: unset;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100%;
  min-height: 44px;
  padding: 6px 12px;
  cursor: pointer;
}
.menciones-op + .menciones-op { border-top: 1px solid var(--color-border-soft, var(--color-border)); }
.menciones-op.activa, .menciones-op:hover, .menciones-op:focus-visible { background: var(--color-accent-soft); }
.menciones-nombre { font-weight: 600; color: var(--color-fg); overflow-wrap: anywhere; }
.menciones-papel { font-size: 12px; color: var(--color-fg-secondary); }
.menciones-vacio { margin: 0; padding: 12px; font-size: 13px; color: var(--color-fg-secondary); }
mark.mencion {
  background: var(--color-accent-soft);
  color: inherit;
  font-weight: 600;
  border-radius: 4px;
  padding: 0 2px;
}
/* La nota interna que el Área ve en su ficha: solo técnicos y ella. */
.sol-msg.sol-msg-interna {
  border-left: 3px solid var(--color-warning);
  background: var(--color-warning-soft);
}
.sol-interna-marca {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  font-weight: 600;
  color: var(--color-warning-fg);
}
.sol-interna-marca svg { width: 12px; height: 12px; }
/* «Responder solo a técnicos» en la ficha del Área. */
.sol-destino { display: flex; flex-wrap: wrap; gap: 8px 16px; margin: 0 0 8px; border: 0; padding: 0; }
.sol-destino label { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; cursor: pointer; }
/* «Te han mencionado» en Hoy (2026-11-09). */
.hoy-menciones-mas { margin: 8px 0 0; font-size: 13px; color: var(--color-fg-secondary); }
.hoy-menciones-vistas { margin-top: 8px; display: flex; justify-content: flex-end; }
.hoy-menciones-vistas .btn { min-height: 44px; }
