/* ============================================================
   Centro de Soporte Experiencity
   Sistema visual: consola de operaciones / centro de incidencias
   ============================================================ */

:root {
  --bg: #f1f4f9;
  --card: #ffffff;
  --input-bg: #ffffff;
  --text: #101828;
  --text-soft: #364152;
  --muted: #667085;
  --border: #e3e8ef;
  --border-soft: #edf1f7;
  --row-hover: #f8faff;
  --dotgrid-color: rgba(14, 116, 144, 0.05);
  --tooltip-bg: #0b1220;
  /* Logo grande de Experiencity de fondo en el contenido principal (a
     petición de Javier: no solo en el menú lateral, también "en el resto
     de la pantalla"). Ya lleva el alfa muy bajo horneado en el propio PNG
     (ver public/assets/logo-experiencity-watermark-*.png), así que aquí
     solo hace falta elegir qué versión (oscura/clara) toca según el tema. */
  --watermark-logo: url('/assets/logo-experiencity-watermark-dark.png');

  /* Teal/violeta de "consola de operaciones": el mismo espíritu que el
     azul corporativo de antes, pero con la personalidad real de la marca
     (el teal es el mismo tono que usa Experiencity para Valencia en su
     propia web; el violeta es el de Málaga). Rojo/ámbar de emergencias
     intactos: son la señal de "esto es urgente" en toda la app y no se
     deben mezclar con el color "de marca". */
  --primary: #0e7490;
  --primary-dark: #155e75;
  --primary-soft: #e0f5f8;
  --primary-glow: rgba(14, 116, 144, 0.28);
  --accent: #7c3aed;
  --accent-soft: #f1e9fd;

  /* Color de acento por departamento/área de quien ha iniciado sesión (ver
     public/js/api.js: departmentInfoForUser, y más abajo los bloques
     [data-department]). Por defecto es el mismo --primary de siempre, así
     que Tecnología (el departamento "por defecto") no cambia nada; solo los
     bloques [data-department="..."] de más abajo lo redefinen para los
     demás departamentos. */
  --department-accent: var(--primary);

  --danger: #d92d20;
  --danger-soft: #fef0ee;
  --success: #12805c;
  --success-soft: #e7f7ef;
  --warning: #b45309;
  --warning-soft: #fef3e2;
  --info: #0e7490;
  --info-soft: #e0f5f8;
  --priority-neutral-soft: #eef1f6;

  --sidebar-bg: #0b1220;
  --sidebar-bg-soft: #121a2c;
  --sidebar-text: #aab4c8;
  --sidebar-text-active: #ffffff;
  --sidebar-border: #1d2740;

  --radius: 12px;
  --radius-sm: 8px;
  --shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.04);
  --shadow-md: 0 2px 4px rgba(16, 24, 40, 0.04), 0 8px 20px rgba(16, 24, 40, 0.06);
  --font: "Inter", -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

/* ---------- Modo oscuro (estilo "Argus") ----------
   Se activa poniendo data-theme="dark" en <html> (ver /js/theme.js).
   Reutiliza el mismo sidebar oscuro que ya existía en el modo claro,
   pero ahora también el contenido principal pasa a un negro casi puro,
   sin "salto" de color entre el menú lateral y el resto de la página. */
:root[data-theme="dark"] {
  --bg: #0a0710;
  --card: #17101f;
  --input-bg: #1d1528;
  --text: #f1ecf7;
  --text-soft: #d6c9e6;
  --muted: #a698ba;
  --border: #2c2138;
  --border-soft: #201830;
  --row-hover: rgba(255, 255, 255, 0.04);
  --dotgrid-color: rgba(212, 24, 61, 0.05);
  --tooltip-bg: #241a30;
  --watermark-logo: url('/assets/logo-experiencity-watermark-light.png');

  /* Estilo "oscuro cinematográfico" (propuesta aprobada por Javier en
     agosto de 2026: carmesí + dorado, tirando a la estética de las propias
     salas de terror/misterio de Experiencity, en vez del cian genérico de
     "consola de operaciones" que había antes). Carmesí como color principal
     (enlaces, estado activo del menú), dorado como acento secundario
     (highlights, gradientes, y también el aviso "normal"). */
  --primary: #ff6b85;
  --primary-dark: #ff8fa3;
  --primary-soft: rgba(212, 24, 61, 0.18);
  --primary-glow: rgba(255, 107, 133, 0.4);
  --accent: #d4a017;
  --accent-soft: rgba(212, 160, 23, 0.16);

  --danger: #ff6b85;
  --danger-soft: rgba(212, 24, 61, 0.16);
  --success: #3ba676;
  --success-soft: rgba(59, 166, 118, 0.14);
  --warning: #d4a017;
  --warning-soft: rgba(212, 160, 23, 0.14);
  --info: #8ea6e0;
  --info-soft: rgba(142, 166, 224, 0.16);
  --priority-neutral-soft: rgba(255, 255, 255, 0.06);

  --sidebar-bg: #0a0710;
  --sidebar-bg-soft: #0a0710;
  --sidebar-text: #b9acc9;
  --sidebar-text-active: #ffffff;
  --sidebar-border: #201830;

  --shadow-sm: none;
  --shadow-md: 0 8px 26px rgba(0, 0, 0, 0.55);
}

/* ---------- Color de acento por departamento ----------
   Se activa con data-department="..." en <html> (ver public/js/api.js:
   departmentInfoForUser, que decide la clave a partir del departamento del
   director o de la primera área del técnico). Tecnología es el
   departamento "por defecto" y a propósito NO tiene bloque aquí: se queda
   con --department-accent = --primary de siempre (ver el :root de arriba),
   así que su aspecto no cambia nada con este añadido.
   Colores comprobados con el validador de paleta del equipo para que se
   distingan bien entre sí, incluso con daltonismo (ver
   propuesta-colores-departamento.html, aprobada por Javier en agosto de
   2026); cada departamento tiene un tono para modo claro y otro más suave
   para modo oscuro, igual que ya hace el resto de la paleta. */
:root[data-department="mantenimiento"] { --department-accent: #eb6834; }
:root[data-department="marketing"] { --department-accent: #4a3aa7; }
:root[data-department="construccion"] { --department-accent: #eda100; }
:root[data-department="rrhh"] { --department-accent: #e87ba4; }
:root[data-department="coordinacion"] { --department-accent: #1a9c6b; }

:root[data-theme="dark"][data-department="mantenimiento"] { --department-accent: #d95926; }
:root[data-theme="dark"][data-department="marketing"] { --department-accent: #9085e9; }
:root[data-theme="dark"][data-department="construccion"] { --department-accent: #c98500; }
:root[data-theme="dark"][data-department="rrhh"] { --department-accent: #d55181; }
:root[data-theme="dark"][data-department="coordinacion"] { --department-accent: #0fbf9e; }

/* ---------- Modo daltónico ----------
   Se activa con data-colorblind="true" en <html> (independiente del tema
   claro/oscuro: se puede combinar con cualquiera de los dos). Solo redefine
   los colores de estado (peligro/aviso/éxito/info), que son los que en el
   resto de la app dependen de distinguir rojo/ámbar/verde por color puro.
   Paleta de Okabe-Ito (referencia habitual para gráficos/UI aptos para
   daltonismo: https://jfly.uni-koeln.de/color/), pensada para distinguirse
   bien tanto en protanopia/deuteranopia como en tritanopia. */
:root[data-colorblind="true"] {
  --danger: #d55e00;
  --danger-soft: #fbe6d8;
  --warning: #e69f00;
  --warning-soft: #fcefd6;
  --success: #009e73;
  --success-soft: #d9f2ec;
  --info: #0072b2;
  --info-soft: #dceaf5;
}
:root[data-theme="dark"][data-colorblind="true"] {
  --danger: #ff8a4d;
  --danger-soft: rgba(255, 138, 77, 0.16);
  --warning: #ffb84d;
  --warning-soft: rgba(255, 184, 77, 0.16);
  --success: #33c79a;
  --success-soft: rgba(51, 199, 154, 0.16);
  --info: #7fcbef;
  --info-soft: rgba(127, 203, 239, 0.16);
}

/* ---------- Tamaño de letra y tipografía accesible ----------
   Ver public/js/api.js (applyFontSize/applyDyslexiaFont). --exp-font-scale
   se aplica al elemento raíz para que rem/em escale con él en toda la app;
   font-accesible es una alternativa de trazo simple y espaciado más
   generoso entre letras (aproximación con fuentes ya instaladas en
   cualquier sistema, sin depender de descargar ninguna fuente externa). */
:root { --exp-font-scale: 100%; }
html { font-size: var(--exp-font-scale); }
html.font-accesible, html.font-accesible body {
  font-family: Verdana, "Comic Sans MS", "Segoe UI", Arial, sans-serif;
  letter-spacing: 0.02em;
  line-height: 1.6;
}

/* ---------- Barra de carga superior ---------- */
#top-loading-bar {
  position: fixed;
  top: 0; left: 0;
  height: 3px;
  width: 0%;
  background: linear-gradient(90deg, var(--primary), var(--accent));
  z-index: 400;
  opacity: 0;
  transition: width 0.4s ease, opacity 0.2s ease;
}
#top-loading-bar.active {
  width: 70%;
  opacity: 1;
  transition: width 8s cubic-bezier(0.1, 0.6, 0.2, 1);
}

/* ---------- Vista compacta de tabla ---------- */
body.compact-table table td, body.compact-table table th { padding: 6px 10px !important; }
body.compact-table table { font-size: 0.86rem; }

/* ---------- Barra visual de SLA ---------- */
.sla-bar { width: 100%; height: 5px; border-radius: 4px; background: var(--priority-neutral-soft); overflow: hidden; margin-top: 4px; }
.sla-bar-fill { height: 100%; border-radius: 4px; transition: width 0.3s ease; }
.sla-bar-fill-ok { background: var(--success); }
.sla-bar-fill-warning { background: var(--warning); }
.sla-bar-fill-danger { background: var(--danger); }

/* ---------- Indicador de color por departamento ---------- */
.dept-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 6px;
  flex-shrink: 0;
  vertical-align: middle;
}

/* ---------- Vista de tablero (Kanban) por estado ---------- */
.kanban-board {
  display: flex;
  gap: 14px;
  overflow-x: auto;
  padding-bottom: 4px;
  align-items: flex-start;
}
.kanban-column {
  flex: 1 1 240px;
  min-width: 240px;
}
.kanban-column-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 10px;
  padding: 0 4px;
}
.kanban-cards { display: flex; flex-direction: column; gap: 10px; }
.kanban-card { padding: 12px 14px; margin-bottom: 0; }
.kanban-card:hover { background: var(--row-hover); }
.kanban-card-title { font-size: 0.9rem; font-weight: 600; margin-bottom: 8px; }
.kanban-card-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-size: 0.78rem;
  color: var(--muted);
  margin-bottom: 6px;
}

/* ---------- Resaltado en vivo (fila que acaba de cambiar) ---------- */
@keyframes row-flash-anim {
  0% { background: var(--primary-soft); }
  100% { background: transparent; }
}
.row-flash { animation: row-flash-anim 1.6s ease-out; }

/* ---------- Sugerencias / colapso de sidebar / versión ---------- */
.suggestion-btn {
  width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid var(--border); background: var(--card);
  cursor: pointer; font-size: 15px; display: inline-flex; align-items: center; justify-content: center;
}
.suggestion-btn:hover { background: var(--row-hover); }
.sidebar-collapse-btn {
  margin: 0 12px 8px 12px; padding: 8px; border-radius: var(--radius-sm);
  border: 1px solid var(--sidebar-border); background: transparent; color: var(--sidebar-text);
  cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.sidebar-collapse-btn:hover { background: rgba(255, 255, 255, 0.06); color: var(--sidebar-text-active); }
.sidebar-collapse-btn svg { width: 16px; height: 16px; }
.sidebar-version {
  display: block;
  width: 100%;
  font-family: inherit;
  font-size: 0.68rem;
  color: var(--sidebar-text);
  opacity: 0.6;
  text-align: center;
  margin-top: 6px;
  background: none;
  border: none;
  padding: 2px 0;
  cursor: pointer;
}
.sidebar-version:hover { opacity: 1; text-decoration: underline; }
.app-shell.sidebar-collapsed .sidebar { width: 72px; }
.app-shell.sidebar-collapsed .sidebar .brand-text,
.app-shell.sidebar-collapsed .sidebar nav a span,
.app-shell.sidebar-collapsed .sidebar .who,
.app-shell.sidebar-collapsed .sidebar .sidebar-version,
.app-shell.sidebar-collapsed .sidebar #logout-link span,
.app-shell.sidebar-collapsed .sidebar .nav-section-label {
  display: none;
}
.app-shell.sidebar-collapsed .sidebar .user-chip { justify-content: center; }
@media (max-width: 900px) {
  /* En móvil el sidebar ya es un cajón deslizante aparte: el botón de
     plegado de escritorio no aplica ahí y solo estorbaría. */
  .sidebar-collapse-btn { display: none; }
}

:root[data-theme="dark"] .card,
:root[data-theme="dark"] .stat-card {
  border-color: var(--border);
}

/* Foto real de una sala de Experiencity de fondo en el menú lateral, muy
   oscurecida para no restar legibilidad: es la misma dirección visual que
   Javier aprobó en la propuesta de estilo (agosto de 2026). Solo en modo
   oscuro: el sidebar en modo claro se queda como estaba. */
:root[data-theme="dark"] .sidebar {
  background-image:
    linear-gradient(180deg, rgba(10, 7, 16, 0.88) 0%, rgba(10, 7, 16, 0.97) 55%, rgba(10, 7, 16, 1) 100%),
    url('https://experiencity.es/images/catalogo-escape-room-3.jpg');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

:root[data-theme="dark"] .sidebar .brand .mark {
  box-shadow: 0 0 0 4px rgba(212, 24, 61, 0.22);
}

:root[data-theme="dark"] .sidebar nav a.active {
  background: rgba(212, 24, 61, 0.2);
  border-left-color: var(--primary);
}
:root[data-theme="dark"] .sidebar nav a.active svg {
  color: var(--primary);
}

/* Departamento/área de quien ha iniciado sesión: cada uno tiene su propia
   foto de fondo en el menú lateral (mismo oscurecido en degradado que ya
   lleva la foto de Tecnología, justo arriba, para que el texto siga
   leyéndose igual de bien) — en los dos temas, porque el menú lateral ya es
   oscuro tanto en claro como en oscuro. Tecnología es el departamento "por
   defecto" (data-department="tecnologia" no tiene bloque propio aquí), así
   que sigue exactamente con su foto de siempre, sin cambios. Fotos de banco
   libre (Unsplash), elegidas por Javier entre varias propuestas en agosto
   de 2026; buscan que cada departamento se reconozca por el TEMA de la foto
   (herramientas, personas, difusión, taller de construcción de sets), no
   solo por el color. */
:root[data-department="mantenimiento"] .sidebar {
  background-image:
    linear-gradient(180deg, rgba(10, 7, 16, 0.72) 0%, rgba(10, 7, 16, 0.92) 55%, rgba(10, 7, 16, 0.98) 100%),
    url('https://images.unsplash.com/photo-1685320198649-781e83a61de4?auto=format&fit=crop&w=900&q=70');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
:root[data-department="rrhh"] .sidebar {
  background-image:
    linear-gradient(180deg, rgba(10, 7, 16, 0.72) 0%, rgba(10, 7, 16, 0.92) 55%, rgba(10, 7, 16, 0.98) 100%),
    url('https://images.unsplash.com/photo-1758873269317-51888e824b28?auto=format&fit=crop&w=900&q=70');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
:root[data-department="marketing"] .sidebar {
  background-image:
    linear-gradient(180deg, rgba(10, 7, 16, 0.72) 0%, rgba(10, 7, 16, 0.92) 55%, rgba(10, 7, 16, 0.98) 100%),
    url('https://images.unsplash.com/photo-1745848413099-13adc3aaf308?auto=format&fit=crop&w=900&q=70');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
/* Construcción: a propósito NO es una obra genérica (grúas, excavadoras) —
   es un taller de carpintería, más parecido a como de verdad se construyen
   los decorados/sets de un escape room, que es lo que hace este
   departamento en Experiencity. */
:root[data-department="construccion"] .sidebar {
  background-image:
    linear-gradient(180deg, rgba(10, 7, 16, 0.72) 0%, rgba(10, 7, 16, 0.92) 55%, rgba(10, 7, 16, 0.98) 100%),
    url('https://images.unsplash.com/photo-1779031242515-205111711b23?auto=format&fit=crop&w=900&q=70');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
:root[data-department="coordinacion"] .sidebar {
  background-image:
    linear-gradient(180deg, rgba(10, 7, 16, 0.72) 0%, rgba(10, 7, 16, 0.92) 55%, rgba(10, 7, 16, 0.98) 100%),
    url('https://images.unsplash.com/photo-1758876021444-3885d0a2539f?auto=format&fit=crop&w=900&q=70');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* Marca de agua del logo de Experiencity sobre la foto de cada
   departamento (pedido explícito de Javier: que las fotos no sean "de
   banco" sueltas, sino que se sientan de la propia marca). Reutiliza el
   mismo logo que ya se ve arriba del todo del menú (invertido a blanco
   igual que ahí), pero pequeño y semitransparente, para que no compita con
   la navegación. Tecnología no entra aquí: sigue igual que siempre. El .sidebar ya tiene
   position: sticky (ver más abajo), que también sirve de referencia para
   este ::after en position: absolute, así que no hace falta tocar nada
   más. */
:root[data-department]:not([data-department="tecnologia"]) .sidebar::after {
  content: "";
  position: absolute;
  right: 16px;
  /* A media altura (no arriba, que ya lleva la marca de la cabecera, ni
     abajo, que ya lleva el chip de usuario/versión): así no choca con
     ningún otro elemento del menú, sea cual sea el número de enlaces o el
     alto de la ventana. */
  top: 50%;
  transform: translateY(-50%);
  width: 90px;
  height: 28px;
  background-image: url('/assets/logo-experiencity.png');
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  filter: brightness(0) invert(1);
  opacity: 0.28;
  pointer-events: none;
}

:root[data-department]:not([data-department="tecnologia"]) .sidebar nav a.active {
  background: color-mix(in srgb, var(--department-accent) 22%, transparent);
  border-left-color: var(--department-accent);
}
:root[data-department]:not([data-department="tecnologia"]) .sidebar nav a.active svg {
  color: var(--department-accent);
}

/* Títulos con un poco más de carácter "de cartel" en modo oscuro, sin tocar
   el modo claro. Se deja en un tamaño y peso conservadores: sigue siendo
   una herramienta de trabajo que hay que leer rápido, no un póster. */
:root[data-theme="dark"] h1 {
  font-family: 'Cinzel', var(--font);
  letter-spacing: 0.01em;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  transition: background 0.15s ease, color 0.15s ease;
}

a { color: var(--primary); text-decoration: none; }
hr { border: none; border-top: 1px solid var(--border); margin: 20px 0; }

/* ---------- Modo "incrustado" ----------
   Las páginas de Usuarios, Base de conocimiento, Auditoría e Infraestructura
   se reutilizan tal cual dentro de las pestañas del panel de Administración
   (en un iframe con ?embed=1): en ese caso se oculta el sidebar y la barra
   superior propios, para no verlos duplicados dentro de la pestaña. */
html.embed-mode .sidebar,
html.embed-mode header.topbar {
  display: none;
}
html.embed-mode .app-shell {
  min-height: 0;
}
html.embed-mode main {
  padding: 4px 4px 24px;
  max-width: none;
}

/* ---------- Estructura general: sidebar + columna principal ---------- */

.app-shell {
  display: flex;
  min-height: 100vh;
}

.sidebar {
  width: 240px;
  flex-shrink: 0;
  background: linear-gradient(180deg, var(--sidebar-bg) 0%, var(--sidebar-bg-soft) 100%);
  color: var(--sidebar-text);
  display: flex;
  flex-direction: column;
  padding: 20px 14px;
  position: sticky;
  top: 0;
  height: 100vh;
  transition: width 0.18s ease;
}

.sidebar .brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 10px 22px;
  color: var(--sidebar-text-active);
}

.sidebar .brand .mark {
  width: 34px;
  height: 34px;
  border-radius: 9px;
  background: linear-gradient(135deg, var(--primary) 0%, var(--accent) 100%);
  background-size: 200% 200%;
  animation: brand-shift 6s ease infinite;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 1rem;
  color: #fff;
  flex-shrink: 0;
  /* El sidebar es siempre oscuro (en los dos temas), así que este brillo
     no se theming: va fijo en cian, como el resto de acentos "sobre
     fondo oscuro" de esta insignia y del active-state del menú. */
  box-shadow: 0 0 0 4px rgba(34, 211, 238, 0.16);
}

.sidebar .brand .mark img {
  width: 58%;
  height: 58%;
  object-fit: contain;
  /* El logo es negro sobre fondo transparente; en la insignia degradada lo
     invertimos a blanco para que se lea bien. */
  filter: brightness(0) invert(1);
}

.sidebar .brand .brand-wordmark {
  display: block;
  height: 15px;
  width: auto;
  margin-bottom: 4px;
  filter: brightness(0) invert(1);
}

@keyframes brand-shift {
  0%, 100% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
}

.sidebar .brand .brand-text {
  line-height: 1.2;
}

.sidebar .brand .brand-text .name {
  font-weight: 700;
  font-size: 0.95rem;
}

.sidebar .brand .brand-text .tag {
  font-size: 0.72rem;
  color: var(--sidebar-text);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.sidebar .nav-section-label {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: #5b6785;
  padding: 14px 12px 6px;
  font-weight: 700;
}

.sidebar nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.sidebar nav a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  color: var(--sidebar-text);
  font-weight: 500;
  font-size: 0.88rem;
  border-left: 2px solid transparent;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.sidebar nav a svg { width: 17px; height: 17px; flex-shrink: 0; opacity: 0.85; }

.sidebar nav a:hover {
  background: rgba(255, 255, 255, 0.06);
  color: var(--sidebar-text-active);
}

/* La sección activa se marca con una barra a la izquierda, como el
   indicador de canal seleccionado en una consola, además del fondo
   resaltado (igual que antes, pero ahora en cian en vez de azul). */
.sidebar nav a.active {
  background: rgba(34, 211, 238, 0.16);
  color: var(--sidebar-text-active);
  border-left-color: #22d3ee;
}
.sidebar nav a.active svg { opacity: 1; color: #22d3ee; }

.sidebar .sidebar-spacer { flex: 1; }

.sidebar .sidebar-footer {
  border-top: 1px solid var(--sidebar-border);
  padding-top: 14px;
  margin-top: 10px;
}

.sidebar .user-chip {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  /* Es un <button>: quitamos todo el estilo por defecto para que siga
     pareciendo el mismo "chip" de siempre, pero ahora se pueda pulsar. */
  width: 100%;
  border: none;
  background: none;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.15s;
}
.sidebar .user-chip:hover { background: rgba(255, 255, 255, 0.06); }

.sidebar .user-chip .avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  font-weight: 700;
  flex-shrink: 0;
}

.sidebar .user-chip .who { line-height: 1.25; overflow: hidden; }
.sidebar .user-chip .who .u-name { font-size: 0.82rem; font-weight: 600; color: var(--sidebar-text-active); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidebar .user-chip .who .u-role { font-size: 0.72rem; color: var(--sidebar-text); }

.sidebar #logout-link {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  color: var(--sidebar-text);
  font-size: 0.82rem;
  font-weight: 500;
}
.sidebar #logout-link:hover { background: rgba(255, 255, 255, 0.06); color: var(--sidebar-text-active); }
.sidebar #logout-link svg { width: 15px; height: 15px; }

.main-col {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

header.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--card);
  border-bottom: 1px solid var(--border);
  padding: 16px 28px;
  position: sticky;
  top: 0;
  z-index: 5;
}

header.topbar .page-title {
  font-weight: 700;
  font-size: 1.05rem;
  display: flex;
  align-items: center;
  gap: 10px;
}

header.topbar .page-title .dot-live {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--success);
  box-shadow: 0 0 0 3px var(--success-soft);
}

/* La "pastilla" de departamento/área: usa --department-accent (definido
   arriba), así que cambia de color sola según quién haya iniciado sesión,
   sin tener que repetir la lógica aquí. Tecnología usa el mismo --primary
   de siempre (teal en modo claro, el carmesí ya aprobado en modo oscuro),
   así que sigue viéndose "de marca" y no como un color inventado nuevo. */
header.topbar .top-meta {
  font-size: 0.78rem;
  font-weight: 600;
  padding: 4px 12px;
  border-radius: 20px;
  background: color-mix(in srgb, var(--department-accent) 16%, transparent);
  color: var(--department-accent);
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
header.topbar .top-meta svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

/* Pastilla convertida en botón cuando quien ha iniciado sesión puede
   cambiar de departamento en vista previa (ver allowedPreviewKeys en
   public/js/api.js): mismo aspecto que la pastilla normal, solo añade el
   cursor y la flechita de "desplegable". */
header.topbar .top-meta-btn {
  border: none;
  cursor: pointer;
  font-family: inherit;
}
header.topbar .top-meta-btn svg:last-child {
  width: 11px;
  height: 11px;
  margin-left: -1px;
  opacity: 0.75;
}

.dept-switcher {
  position: relative;
}
.dept-switcher-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 40;
  min-width: 200px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.28);
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.dept-switcher-option {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 10px;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--text);
  font-size: 0.82rem;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}
.dept-switcher-option svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}
.dept-switcher-option:hover {
  background: var(--surface-hover, rgba(127, 127, 127, 0.12));
}
.dept-switcher-option.active {
  color: var(--department-accent);
  background: color-mix(in srgb, var(--department-accent) 14%, transparent);
}
.dept-switcher-option.dept-switcher-reset {
  margin-top: 4px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
  color: var(--text-soft);
  font-weight: 500;
}

main {
  max-width: 1440px;
  width: 100%;
  margin: 0 auto;
  padding: 28px 28px 60px;
  min-height: calc(100vh - 66px);
  /* Cuatro capas: la trama de puntos de siempre (se repite, va delante) y
     TRES copias del logo grande de Experiencity (arriba/medio/abajo de la
     ventana), en vez de una sola: Javier notó que con una sola, en
     pantallas con tarjetas (como Inicio) casi siempre queda tapada por el
     propio contenido y no se ve. Con tres repartidas, siempre hay alguna
     en un hueco libre. El PNG del logo ya lleva el alfa muy bajo horneado
     en el propio archivo (ver la variable --watermark-logo más arriba),
     así que aquí no hace falta tocar ninguna opacidad. */
  background-image:
    radial-gradient(circle, var(--dotgrid-color) 1px, transparent 1px),
    var(--watermark-logo),
    var(--watermark-logo),
    var(--watermark-logo);
  background-size: 22px 22px, 680px auto, 680px auto, 680px auto;
  /* Las tres copias del logo van "fixed" (fijas respecto a la ventana, no
     al scroll de la página), repartidas en altura (18%/50%/82% del alto de
     la ventana) para que siempre haya alguna visible sin depender de lo
     larga que sea cada pantalla ni de cuánto se haya bajado. El +120px en
     horizontal compensa el ancho del menú lateral (240px), para que
     queden centradas en el hueco de la derecha ("el resto de la
     pantalla"), no en el centro de toda la ventana. */
  background-position: 0 0, calc(50% + 120px) 18%, calc(50% + 120px) 50%, calc(50% + 120px) 82%;
  background-repeat: repeat, no-repeat, no-repeat, no-repeat;
  background-attachment: scroll, fixed, fixed, fixed;
}

/* ---------- Animaciones de entrada ---------- */

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

.card, .stat-card, .type-card {
  animation: fade-up 0.35s ease both;
}
.stat-grid .stat-card:nth-child(1) { animation-delay: 0s; }
.stat-grid .stat-card:nth-child(2) { animation-delay: 0.05s; }
.stat-grid .stat-card:nth-child(3) { animation-delay: 0.1s; }
.stat-grid .stat-card:nth-child(4) { animation-delay: 0.15s; }

/* ---------- Indicador "en vivo" con pulso ---------- */

header.topbar .page-title .dot-live {
  position: relative;
}
header.topbar .page-title .dot-live::after {
  content: "";
  position: absolute;
  top: -4px;
  left: -4px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 1.5px solid var(--success);
  animation: pulse-ring 2s cubic-bezier(0.2, 0.6, 0.4, 1) infinite;
}

@keyframes pulse-ring {
  0% { transform: scale(0.4); opacity: 0.9; }
  80% { transform: scale(1.4); opacity: 0; }
  100% { transform: scale(1.4); opacity: 0; }
}

.top-meta-group {
  display: flex;
  align-items: center;
  gap: 18px;
}

.theme-toggle-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--text-soft);
  cursor: pointer;
  padding: 0;
  margin: 0;
  flex-shrink: 0;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}

.notif-wrap {
  position: relative;
}

.notif-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 999px;
  background: #e0433d;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
}

.notif-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 340px;
  max-height: 420px;
  overflow-y: auto;
  background: var(--card-bg, #fff);
  border: 1px solid var(--border-color, #e2e2e2);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  z-index: 1000;
}

.notif-dropdown-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border-color, #e2e2e2);
}

.notif-mark-all {
  background: none;
  border: none;
  color: var(--accent-color, #2563eb);
  font-size: 12px;
  cursor: pointer;
  padding: 0;
}

.notif-item {
  display: block;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border-color, #f0f0f0);
  text-decoration: none;
  color: inherit;
}

.notif-item:last-child {
  border-bottom: none;
}

.notif-item:hover {
  background: var(--hover-bg, #f5f5f5);
}

.notif-item.unread {
  background: var(--unread-bg, #eef4ff);
}

.notif-item-msg {
  font-size: 13px;
  line-height: 1.4;
  margin-bottom: 4px;
}

.notif-item-date {
  font-size: 11px;
  color: var(--text-secondary, #888);
}

.theme-toggle-btn:hover {
  background: var(--primary-soft);
  border-color: var(--primary);
  color: var(--primary);
  box-shadow: none;
}
.theme-toggle-btn svg { width: 17px; height: 17px; }

/* Botón de hamburguesa del topbar: solo se ve en móvil (ver @media más
   abajo), abre/cierra el cajón del menú lateral. Mismo estilo redondeado que
   el botón de sol/luna para que no desentone en la misma barra. */
.mobile-nav-toggle {
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--text-soft);
  cursor: pointer;
  padding: 0;
  margin: 0 4px 0 0;
  flex-shrink: 0;
}
.mobile-nav-toggle svg { width: 18px; height: 18px; }
.mobile-nav-toggle:hover { background: var(--primary-soft); border-color: var(--primary); color: var(--primary); }

.live-clock-group {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  line-height: 1.3;
}

.live-date {
  font-size: 0.68rem;
  color: var(--muted);
}

.live-clock {
  font-family: "SF Mono", "Consolas", monospace;
  font-size: 0.82rem;
  color: var(--text-soft);
  font-weight: 600;
  letter-spacing: 0.02em;
}

/* ---------- Prioridad alta: aviso pulsante ---------- */

.badge.priority-alta {
  animation: glow-pulse 1.8s ease-in-out infinite;
}
@keyframes glow-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(217, 45, 32, 0.25); }
  50% { box-shadow: 0 0 0 4px rgba(217, 45, 32, 0.12); }
}

/* ---------- Contadores animados ---------- */

.stat-card .stat-value { transition: color 0.2s; }

/* ---------- Tarjetas ---------- */

.card {
  background: var(--card);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: 22px;
  margin-bottom: 20px;
}

h1 { font-size: 1.4rem; margin: 0 0 4px; letter-spacing: -0.01em; }
h2 { font-size: 1.05rem; margin: 0 0 14px; letter-spacing: -0.01em; }
.page-subtitle { color: var(--muted); font-size: 0.92rem; margin: 0 0 20px; }

.page-header-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.page-header-row h1 { margin-bottom: 4px; }
.page-header-row .page-subtitle { margin-bottom: 0; }
.page-header-row button { margin-top: 2px; white-space: nowrap; }

/* ---------- Métricas del panel ---------- */

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px;
  margin-bottom: 22px;
}

.stat-card {
  background: var(--card);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: 18px 20px;
  display: flex;
  align-items: center;
  gap: 14px;
}

.stat-card .stat-icon {
  width: 42px;
  height: 42px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.stat-card .stat-icon svg { width: 20px; height: 20px; }

.stat-card.total .stat-icon { background: var(--primary-soft); color: var(--primary); }
.stat-card.abierto .stat-icon { background: var(--warning-soft); color: var(--warning); }
.stat-card.en_proceso .stat-icon { background: var(--info-soft); color: var(--info); }
.stat-card.cerrado .stat-icon { background: var(--success-soft); color: var(--success); }
.stat-card.avg-resolution .stat-icon { background: var(--accent-soft, var(--primary-soft)); color: var(--accent); }

.stat-card .stat-value { font-size: 1.5rem; font-weight: 800; line-height: 1.1; letter-spacing: -0.02em; }
.stat-card .stat-value-text { font-size: 1.25rem; }
.stat-card .stat-label { font-size: 0.78rem; color: var(--muted); font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em; }

@media (max-width: 900px) {
  .stat-grid { grid-template-columns: repeat(2, 1fr); }
}

/* ---------- Panel de estadísticas (gráficos del dashboard) ---------- */

.stats-panels {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
  margin-bottom: 22px;
}

.chart-card-wide { grid-column: 1 / -1; }

@media (max-width: 900px) {
  .stats-panels { grid-template-columns: 1fr; }
}

.chart-card { margin-bottom: 0; }

.chart-empty {
  color: var(--muted);
  font-size: 0.88rem;
  padding: 20px 0;
  text-align: center;
}

.bar-row {
  display: grid;
  grid-template-columns: minmax(90px, 160px) 1fr 56px;
  align-items: center;
  gap: 10px;
  padding: 7px 0;
  cursor: default;
}

.bar-row-label {
  font-size: 0.84rem;
  color: var(--text-soft);
  font-weight: 600;
  line-height: 1.25;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.bar-track {
  position: relative;
  height: 14px;
  background: var(--border-soft);
  border-radius: 7px;
  overflow: hidden;
  display: flex;
}

.bar-fill {
  height: 100%;
  border-radius: 7px;
  transition: width 0.4s ease;
}

.stacked-track .stacked-segment {
  border-radius: 0;
}
.stacked-track .stacked-segment:first-child { border-radius: 7px 0 0 7px; }
.stacked-track .stacked-segment:last-child { border-radius: 0 7px 7px 0; }
.stacked-track .stacked-segment:only-child { border-radius: 7px; }
.stacked-track .stacked-segment + .stacked-segment { margin-left: 2px; }

.bar-row-value {
  font-size: 0.82rem;
  color: var(--text-soft);
  font-weight: 700;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.chart-legend {
  display: flex;
  gap: 16px;
  margin-bottom: 12px;
}

.legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.8rem;
  color: var(--text-soft);
  font-weight: 600;
}

.legend-swatch {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  display: inline-block;
}

.line-chart-svg {
  width: 100%;
  height: auto;
  overflow: visible;
}

.chart-grid-line {
  stroke: var(--border-soft);
  stroke-width: 1;
}

.chart-axis-label {
  fill: var(--muted);
  font-size: 10px;
  font-family: var(--font);
}

.line-dot {
  cursor: pointer;
  transition: r 0.15s ease;
}
.line-dot:hover { r: 6; }

.chart-tooltip {
  position: fixed;
  display: none;
  z-index: 50;
  background: var(--tooltip-bg);
  color: #fff;
  border-radius: var(--radius-sm);
  padding: 8px 12px;
  font-size: 0.78rem;
  box-shadow: var(--shadow-md);
  pointer-events: none;
  max-width: 220px;
}

.chart-tooltip-row {
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}
.chart-tooltip-row + .chart-tooltip-row { margin-top: 3px; }

.chart-tooltip-key {
  width: 8px;
  height: 8px;
  border-radius: 2px;
  flex-shrink: 0;
}

.chart-tooltip-label { color: rgba(255, 255, 255, 0.75); }
.chart-tooltip-value { color: #fff; margin-left: auto; }

/* ---------- Lista de tickets abiertos hace más tiempo ---------- */

.oldest-row {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: 14px;
  padding: 11px 4px;
  border-bottom: 1px solid var(--border-soft);
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: background 0.15s ease;
}
.oldest-row:last-child { border-bottom: none; }
.oldest-row:hover { background: var(--bg); }

.oldest-main { min-width: 0; }
.oldest-title {
  font-weight: 700;
  font-size: 0.9rem;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.oldest-meta {
  font-size: 0.78rem;
  color: var(--muted);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.oldest-age {
  font-weight: 800;
  font-size: 0.86rem;
  color: var(--danger);
  white-space: nowrap;
}

/* ---------- Ranking de técnicos (gamificación) ---------- */

.leaderboard-row {
  display: grid;
  grid-template-columns: 40px 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 12px 4px;
  border-bottom: 1px solid var(--border-soft);
}
.leaderboard-row:last-child { border-bottom: none; }

.leaderboard-rank {
  font-size: 0.95rem;
  text-align: center;
  font-weight: 800;
  color: var(--muted);
}
.leaderboard-rank.rank-1 { color: var(--accent); }

.leaderboard-main { min-width: 0; }
.leaderboard-name { font-weight: 700; font-size: 0.92rem; color: var(--text); }
.leaderboard-meta { font-size: 0.8rem; color: var(--muted); margin-top: 2px; }
.leaderboard-meta svg { width: 12px; height: 12px; vertical-align: -1px; }

.leaderboard-badges { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.leaderboard-badge {
  display: inline-flex;
  align-items: center;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
  background: var(--accent-soft, var(--primary-soft));
  color: var(--accent);
}

.leaderboard-points {
  font-weight: 800;
  font-size: 1rem;
  color: var(--accent);
  white-space: nowrap;
}

/* ---------- Login ---------- */

/* La pantalla de login es el único sitio donde nos permitimos ser vistosos
   de verdad (ver frontend-design: "spend your boldness in one place"): una
   rejilla triangular de fondo, un guiño directo al icono de triángulos del
   logo y a la textura de polígonos de la propia web de Experiencity, con
   dos brillos de color (cian + violeta) detrás, como si fuera la pantalla
   de una consola de control vista a través de un cristal facetado. El
   resto de la app se queda deliberadamente más discreta. */
.login-wrapper {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
  padding: 20px;
  background:
    repeating-linear-gradient(60deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 46px),
    repeating-linear-gradient(-60deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 46px),
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 46px),
    radial-gradient(circle at 15% 20%, rgba(34, 211, 238, 0.35), transparent 45%),
    radial-gradient(circle at 85% 80%, rgba(167, 139, 250, 0.32), transparent 45%),
    var(--sidebar-bg);
}

/* Login en modo oscuro: la misma foto real de sala que usa el sidebar,
   con los brillos de color actualizados a carmesí + dorado en vez de
   cian + violeta (ver la nota de arriba sobre el estilo aprobado en
   agosto de 2026). Sigue siendo "el único sitio donde nos permitimos ser
   vistosos": el resto de la app se queda discreta. */
:root[data-theme="dark"] .login-wrapper {
  background:
    repeating-linear-gradient(60deg, rgba(255, 255, 255, 0.04) 0 1px, transparent 1px 46px),
    repeating-linear-gradient(-60deg, rgba(255, 255, 255, 0.04) 0 1px, transparent 1px 46px),
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.04) 0 1px, transparent 1px 46px),
    radial-gradient(circle at 15% 20%, rgba(212, 24, 61, 0.4), transparent 45%),
    radial-gradient(circle at 85% 80%, rgba(212, 160, 23, 0.32), transparent 45%),
    linear-gradient(180deg, rgba(10, 7, 16, 0.86) 0%, rgba(10, 7, 16, 0.96) 100%),
    url('https://experiencity.es/images/catalogo-escape-room-1.jpg');
  background-size: auto, auto, auto, auto, auto, cover, cover;
  background-position: 0 0, 0 0, 0 0, 0 0, 0 0, center, center 30%;
}

.login-card {
  width: 100%;
  max-width: 400px;
  background: var(--card);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
  border: none;
}

.login-card .brand-mark {
  width: 52px;
  height: 52px;
  border-radius: 14px;
  margin: 0 auto 16px;
  background: linear-gradient(135deg, var(--primary) 0%, var(--accent) 100%);
  background-size: 200% 200%;
  animation: brand-shift 6s ease infinite;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-weight: 800;
  font-size: 1.4rem;
  box-shadow: 0 0 0 6px var(--primary-soft);
}

.login-card .brand-mark img {
  width: 58%;
  height: 58%;
  object-fit: contain;
  filter: brightness(0) invert(1);
}

.login-card .brand-wordmark {
  display: block;
  height: 24px;
  width: auto;
  margin: 0 auto 4px;
  transition: filter 0.15s ease;
}

/* El logo es negro sobre fondo transparente: en modo oscuro la tarjeta de
   login pasa a ser oscura, así que hay que invertirlo a blanco para que
   siga siendo legible (igual que ya se hacía en el sidebar). */
:root[data-theme="dark"] .login-card .brand-wordmark {
  filter: brightness(0) invert(1);
}

.login-card .subtitle {
  text-align: center;
  color: var(--muted);
  margin-bottom: 24px;
  font-size: 0.88rem;
}

.login-card .foot-note {
  text-align: center;
  color: var(--muted);
  font-size: 0.75rem;
  margin-top: 18px;
}
.login-card .foot-note a { color: var(--primary); }

/* Bloque separado (fuera de la tarjeta de login, no dentro) que enlaza al
   formulario público de solicitudes (public/solicitud.html). A propósito no
   va dentro de .login-card ni suena a "pedir una cuenta": es una vía
   distinta, para quien nunca va a tener usuario en esta web. */
.public-request-banner {
  width: 100%;
  max-width: 400px;
  text-align: center;
  padding: 20px 24px;
}
.public-request-banner-title {
  font-weight: 700;
  margin-bottom: 6px;
}
.public-request-banner p {
  color: var(--muted);
  font-size: 0.85rem;
  margin: 0 0 14px;
}
.public-request-banner .btn {
  margin-top: 0;
  text-decoration: none;
}

/* Formulario público de solicitudes (public/solicitud.html): mismo estilo de
   tarjeta que el login, pero más ancha porque además del nombre/email lleva
   el selector de tipo de solicitud y sus campos dinámicos. */
.public-form-card {
  max-width: 640px;
  text-align: left;
}
.public-form-card .subtitle { text-align: center; }
#success-view p { margin: 6px 0; }

/* ---------- Formularios ---------- */

label {
  display: block;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-soft);
  margin-bottom: 6px;
  margin-top: 16px;
}

input, select, textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 0.92rem;
  font-family: inherit;
  background: var(--input-bg);
  color: var(--text);
  transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;
}

input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

textarea { min-height: 90px; resize: vertical; }

/* Los checkboxes nunca deben heredar el "width: 100%" de arriba (pensado
   para inputs de texto): sin esto, el cuadradito se estira a todo el ancho
   del campo y se ve descentrado/roto. Ya existían overrides puntuales para
   los sitios donde ya había checkboxes (.checkbox-group, .bulk-select-col,
   .checklist-item); esta regla general los cubre a todos, incluida la
   casilla única de "¿Necesita correo corporativo nuevo?" en
   server/ticketTypes.js. */
input[type="checkbox"] { width: auto; padding: 0; }

button, .btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--primary);
  color: #fff;
  border: none;
  padding: 10px 18px;
  border-radius: var(--radius-sm);
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  margin-top: 20px;
  transition: background 0.15s, transform 0.05s;
}

button:hover, .btn:hover { background: var(--primary-dark); box-shadow: 0 4px 16px var(--primary-glow); }
button:active, .btn:active { transform: translateY(1px); }
button:disabled { opacity: 0.6; cursor: not-allowed; }

button.secondary, .btn.secondary {
  background: transparent;
  color: var(--primary);
  border: 1px solid var(--border);
}
button.secondary:hover, .btn.secondary:hover { background: var(--primary-soft); border-color: var(--primary); }

button.danger { background: var(--danger); }
button.danger:hover { background: #b42318; }

.error-msg {
  color: var(--danger);
  font-size: 0.85rem;
  margin-top: 10px;
  min-height: 1.2em;
}

.success-msg {
  color: var(--success);
  font-size: 0.85rem;
  margin-top: 10px;
}

.checkbox-inline {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 500;
  font-size: 0.88rem;
  margin: 10px 0 0;
}
.checkbox-inline input { width: auto; margin: 0; }

.toolbar {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 18px;
}

.toolbar select { width: auto; margin: 0; }

/* Barra de acciones en bloque (comentar/eliminar varios tickets a la vez):
   solo aparece cuando hay algo marcado, pegada justo encima de la tabla para
   que quede claro a qué lista se refiere. */
.bulk-actions-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--card);
  border: 1px solid var(--primary);
  border-radius: var(--radius);
  padding: 10px 14px;
  margin-bottom: 10px;
  font-size: 0.85rem;
}
.bulk-actions-bar #bulk-actions-count { font-weight: 700; margin-right: auto; }
.bulk-select-col { width: 34px; padding-right: 0 !important; }
.bulk-select-col input[type="checkbox"] { width: 16px; height: 16px; cursor: pointer; margin: 0; }

/* ---------- Tabla de tickets ---------- */

table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 12px 10px; border-bottom: 1px solid var(--border-soft); font-size: 0.88rem; }
th { color: var(--muted); font-weight: 600; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; }
tbody tr { transition: background 0.1s; }
tbody tr:hover td { background: var(--row-hover); }
td.ticket-id { font-family: "SF Mono", "Consolas", monospace; color: var(--muted); font-weight: 600; }
td.ticket-title { font-weight: 600; color: var(--text); }

.unassigned-tag { color: var(--muted); font-size: 0.82rem; font-style: italic; }

/* ---------- Indicadores de urgencia / SLA ---------- */

.urgency-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 8px;
  vertical-align: middle;
}
.urgency-dot-vencido { background: var(--danger); box-shadow: 0 0 0 3px var(--danger-soft); }
.urgency-dot-por_vencer { background: var(--warning); box-shadow: 0 0 0 3px var(--warning-soft); }

tr.urgency-vencido td { background: var(--danger-soft); }
tr.urgency-vencido:hover td { background: var(--danger-soft); }

/* ---------- Filtros rápidos y cola ---------- */

.quick-filters { display: inline-flex; gap: 6px; }
.chip-filter {
  padding: 7px 12px;
  border-radius: 999px;
  border: 1px solid var(--border-soft);
  background: transparent;
  color: var(--muted);
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
  margin: 0;
  transition: all 0.12s;
}
.chip-filter:hover { border-color: var(--primary); color: var(--text); }
.chip-filter.active { background: var(--primary); border-color: var(--primary); color: #fff; }

/* ---------- Dot "en vivo" (topbar) ---------- */

header.topbar .page-title .dot-live.offline {
  background: var(--muted);
  box-shadow: none;
  animation: none;
}
header.topbar .page-title .dot-live.offline::after { display: none; }

/* ---------- Insignias de estado / prioridad ---------- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 0.74rem;
  font-weight: 700;
  white-space: nowrap;
}
.badge::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}

.badge.abierto { background: var(--warning-soft); color: var(--warning); }
.badge.en_proceso { background: var(--info-soft); color: var(--info); }
.badge.cerrado { background: var(--success-soft); color: var(--success); }
.badge.pendiente_revision { background: var(--danger-soft); color: var(--danger); }

.badge.priority-alta { background: var(--danger-soft); color: var(--danger); }
.badge.priority-normal { background: var(--priority-neutral-soft); color: var(--muted); }
.badge.priority-baja { background: var(--priority-neutral-soft); color: var(--muted); }

/* ---------- Detalle de ticket ---------- */

.ticket-detail-grid {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: 20px;
  align-items: start;
}

@media (max-width: 900px) {
  .ticket-detail-grid { grid-template-columns: 1fr; }
}

.ticket-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 6px;
}

.ticket-header .ticket-number {
  font-family: "SF Mono", "Consolas", monospace;
  color: var(--muted);
  font-size: 0.85rem;
  font-weight: 600;
}

.ticket-badges { display: flex; gap: 8px; margin: 10px 0 18px; }

.field-row {
  padding: 10px 0;
  border-bottom: 1px solid var(--border-soft);
}
.field-row:last-child { border-bottom: none; }

.field-row .field-label {
  color: var(--muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-weight: 700;
  margin-bottom: 3px;
}
.field-row .field-value { font-size: 0.92rem; color: var(--text); white-space: pre-wrap; }

.checkbox-group { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 6px; }
.checkbox-group label { display: flex; align-items: center; gap: 6px; font-weight: 500; margin: 0; }
.checkbox-group input { width: auto; }

/* ---------- Comentarios / actividad ---------- */

.comment {
  display: flex;
  gap: 12px;
  padding: 14px 0;
  border-bottom: 1px solid var(--border-soft);
}
.comment:last-child { border-bottom: none; }

.comment .avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--primary-soft);
  color: var(--primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.72rem;
  font-weight: 700;
  flex-shrink: 0;
}

.comment .comment-body { flex: 1; min-width: 0; }
.comment .meta { font-size: 0.78rem; color: var(--muted); margin-bottom: 4px; }
.comment .meta strong { color: var(--text-soft); }
.comment.system { color: var(--muted); }
.comment.system .avatar { background: var(--priority-neutral-soft); color: var(--muted); }
.comment.system .comment-body { font-size: 0.85rem; font-style: italic; }

/* ---------- Comentarios internos (solo equipo de tecnología) ---------- */

.comment.internal {
  background: var(--warning-soft);
  border-radius: var(--radius-sm);
  border-bottom: none;
  padding: 12px 14px;
  margin-bottom: 8px;
}
.comment.internal:last-child { margin-bottom: 0; }

/* ---------- Selector de estrellas (encuesta de satisfacción) ---------- */

.star-picker {
  display: flex;
  gap: 4px;
  margin: 10px 0 4px;
}
.star-picker .star {
  font-size: 1.9rem;
  line-height: 1;
  color: var(--border);
  cursor: pointer;
  transition: color 0.1s ease;
  user-select: none;
}
.star-picker .star.active,
.star-picker .star.hover {
  color: var(--warning);
}

/* ---------- Sugerencias de la base de conocimiento ---------- */

#kb-suggestions {
  background: var(--info-soft);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-sm);
  padding: 14px 16px;
  margin: 6px 0 16px;
}
.kb-suggestions-title { font-weight: 700; font-size: 0.85rem; color: var(--info); margin-bottom: 8px; }
.kb-suggestion { padding: 8px 0; border-top: 1px solid var(--border-soft); }
.kb-suggestion:first-of-type { border-top: none; padding-top: 0; }
.kb-suggestion-title { font-weight: 600; font-size: 0.88rem; color: var(--text); }
.kb-suggestion-body { font-size: 0.82rem; color: var(--muted); margin-top: 2px; white-space: pre-wrap; }

/* ---------- Aviso de posibles tickets similares/duplicados ---------- */

#similar-tickets {
  background: var(--warning-soft);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-sm);
  padding: 14px 16px;
  margin: 6px 0 16px;
}
.similar-tickets-title { font-weight: 700; font-size: 0.85rem; color: var(--warning); margin-bottom: 8px; }
.similar-tickets-list { margin: 0; padding-left: 18px; }
.similar-tickets-list li { font-size: 0.85rem; margin-bottom: 4px; }
.similar-tickets-list a { color: var(--text); font-weight: 600; text-decoration: underline; }
.similar-tickets-list .similar-ticket-date { color: var(--muted); font-size: 0.78rem; white-space: pre-wrap; }

/* ---------- Selector de tipo de ticket (tarjetas) ---------- */

/* Contenedor de las tarjetas de tipo de ticket, ahora agrupadas por área
   (Tecnología, Mantenimiento, RRHH...) desde que el centro de soporte dejó
   de ser solo para Tecnología: ver public/js/new-ticket.js. Cada grupo tiene
   su propia rejilla de tarjetas debajo de una pequeña etiqueta de sección. */
.type-grid {
  display: flex;
  flex-direction: column;
  gap: 18px;
  margin-top: 6px;
}
.type-grid-group-label {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  margin-bottom: 8px;
}
.type-grid-group-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}
@media (max-width: 700px) { .type-grid-group-cards { grid-template-columns: repeat(2, 1fr); } }

.type-card {
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px 12px;
  cursor: pointer;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-soft);
  display: flex;
  align-items: center;
  gap: 10px;
  transition: border-color 0.15s, background 0.15s;
  line-height: 1.25;
}
.type-card .type-icon {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  background: var(--primary-soft);
  color: var(--primary);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.type-card .type-icon svg { width: 15px; height: 15px; }
.type-card:hover { border-color: var(--primary); }
.type-card.selected { border-color: var(--primary); background: var(--primary-soft); color: var(--primary-dark); }

/* Tarjetas de experiencia con imagen promocional (mapa interactivo) */
.type-card.type-card-image {
  flex-direction: column;
  align-items: stretch;
  padding: 0;
  gap: 0;
  overflow: hidden;
  position: relative;
  aspect-ratio: 16 / 10;
}
.type-card.type-card-image .type-card-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.type-card.type-card-image .type-card-img-label {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 10px 12px 8px;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.78), rgba(0, 0, 0, 0));
  color: #fff;
  font-size: 0.82rem;
  font-weight: 700;
  line-height: 1.25;
}
.type-card.type-card-image.selected { box-shadow: 0 0 0 2px var(--primary) inset; }
.type-card.type-card-image .mapa-delete-btn {
  background: rgba(0, 0, 0, 0.5) !important;
  border-radius: 6px !important;
  color: #fff !important;
}

/* ---------- Barra de progreso del ticket (vista empleado) ---------- */

.ticket-progress {
  display: flex;
  align-items: flex-start;
}

.ticket-progress-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  width: 90px;
}

.ticket-progress-dot {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--border);
  border: 2px solid var(--border);
  flex-shrink: 0;
}

.ticket-progress-step.active .ticket-progress-dot {
  background: var(--success);
  border-color: var(--success);
}

.ticket-progress-label {
  font-size: 0.72rem;
  color: var(--muted);
  text-align: center;
  line-height: 1.3;
}

.ticket-progress-step.active .ticket-progress-label {
  color: var(--text);
  font-weight: 600;
}

.ticket-progress-line {
  flex: 1 1 auto;
  height: 2px;
  background: var(--border);
  margin-top: 7px;
  min-width: 12px;
}

.ticket-progress-line.active {
  background: var(--success);
}

/* ---------- Modal ---------- */

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(16, 24, 40, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 100;
}

.modal-card {
  width: 100%;
  max-width: 440px;
  /* Sin esto una tarjeta con contenido largo (p.ej. el historial de
     cambios, que crece con cada version) se salia por debajo de la
     pantalla sin forma de bajar ni subir para verlo entero. */
  max-height: 90vh;
  overflow-y: auto;
}
.modal-card.modal-card-wide {
  max-width: 720px;
  max-height: 90vh;
  overflow-y: auto;
  margin: 0;
}

.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 20px;
}
.modal-actions button { margin-top: 0; }

/* ---------- Estados vacíos ---------- */

.empty-state {
  color: var(--muted);
  text-align: center;
  padding: 40px 0;
  font-size: 0.9rem;
}

/* ---------- Responsive ---------- */

/* Menú lateral en móvil: antes se aplastaba en una fila horizontal con
   scroll (difícil de usar con el dedo y algunos enlaces quedaban cortados
   fuera de la pantalla). Ahora se comporta como un cajón que se abre con el
   botón de hamburguesa del topbar (ver #mobile-nav-toggle en public/js/api.js)
   y se cierra tocando fuera o volviendo a pulsar el botón — el resto de la
   página (tabla de tickets, filtros, mapa...) queda con todo el ancho. */
@media (max-width: 900px) {
  .app-shell { flex-direction: column; }

  .mobile-nav-toggle { display: inline-flex; }

  /* Barra superior en movil: la pastilla de departamento + fecha/hora +
     los 3 botones redondos no cabian en una sola fila sin desbordar hacia
     la derecha, fuera de la pantalla - por eso no se podia tocar nada ahi
     (lo que reporto Javi). Se oculta la fecha/hora (no hace falta en
     movil) y el resto pasa a envolver en vez de salirse. */
  .live-clock-group { display: none; }
  .top-meta-group { flex-wrap: wrap; justify-content: flex-end; gap: 8px; row-gap: 6px; }
  header.topbar .page-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  .sidebar {
    width: min(78vw, 300px);
    height: 100vh;
    position: fixed;
    top: 0;
    left: 0;
    flex-direction: column;
    align-items: stretch;
    overflow-x: hidden;
    overflow-y: auto;
    transform: translateX(-100%);
    transition: transform 0.22s ease;
    z-index: 210;
    box-shadow: 0 0 0 rgba(0, 0, 0, 0);
  }
  .app-shell.nav-open .sidebar { transform: translateX(0); box-shadow: 8px 0 28px rgba(0, 0, 0, 0.35); }

  .nav-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    z-index: 205;
  }
  .app-shell.nav-open .nav-backdrop { display: block; }

  .sidebar nav { flex-direction: column; }
  main { padding: 20px 16px 40px; }
}

@media (min-width: 901px) {
  .mobile-nav-toggle { display: none; }
  .nav-backdrop { display: none; }
}

@media (max-width: 640px) {
  header.topbar { padding: 14px 16px; }
  table, thead, tbody, th, td, tr { display: block; }
  thead { display: none; }
  tr { position: relative; margin-bottom: 12px; border: 1px solid var(--border-soft); border-radius: var(--radius-sm); padding: 8px; padding-right: 42px; }
  td { border-bottom: none; padding: 5px 6px; }
  /* Solo se pinta la etiqueta ("Campo: ") si la celda de verdad tiene un
     data-label — si no, antes salía igual un ": " suelto sin texto delante
     (pasaba en la columna de "Descargar PDF" del historial de informes, que
     no tiene una etiqueta con sentido). */
  td[data-label]:not([data-label=""])::before { content: attr(data-label) ": "; font-weight: 600; color: var(--muted); }

  /* La casilla de selección en bloque no tiene "etiqueta" que mostrar (es
     solo un checkbox), así que en vez de salir como una fila más ("· : ☐")
     se pone flotando en la esquina de la tarjeta. */
  td.bulk-select-col {
    position: absolute;
    top: 8px;
    right: 6px;
    width: auto;
    padding: 0;
  }
  td.bulk-select-col::before { content: none; }
}

/* ---------- Pantalla resumen (wallboard) ---------- */
/* Pensada para una tele/monitor de oficina: sin barra lateral, números
   grandes, se refresca sola (en vivo + cada 30s como red de seguridad). */

.wallboard-body { background: var(--bg); }

.wallboard {
  max-width: 1400px;
  margin: 0 auto;
  padding: 32px 40px 60px;
}

.wallboard-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 28px;
}
.wallboard-brand {
  display: flex;
  align-items: center;
  gap: 12px;
  font-weight: 700;
  font-size: 1.1rem;
  color: var(--text);
}
.wallboard-brand img { width: 36px; height: 36px; border-radius: 8px; }
.wallboard-clock {
  font-family: "SF Mono", "Consolas", monospace;
  font-size: 1.6rem;
  font-weight: 700;
  color: var(--text);
}
.wallboard-header-right { display: flex; align-items: center; gap: 16px; }
.wallboard-sound-toggle {
  background: var(--card);
  border: 1px solid var(--border-soft);
  border-radius: 999px;
  width: 40px;
  height: 40px;
  font-size: 1.1rem;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.wallboard-sound-toggle:hover { background: var(--primary-soft); }

/* Filtro de área en el wallboard (panel compartido: por defecto combina
   todas las áreas, con esto se puede acotar a una en concreto sin salir de
   la pantalla). Mismo estilo "chip oscuro" que el resto de la cabecera. */
.wallboard-area-filter {
  background: var(--card);
  border: 1px solid var(--border-soft);
  border-radius: 999px;
  color: var(--text);
  font-size: 0.85rem;
  font-weight: 600;
  padding: 8px 14px;
  margin: 0;
}

.wallboard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 18px;
  margin-bottom: 28px;
}

.wallboard-card {
  background: var(--card);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 26px 22px;
  text-align: center;
}
.wallboard-card-value { font-size: 3rem; font-weight: 800; line-height: 1; color: var(--text); }
.wallboard-card-label { margin-top: 10px; font-size: 0.9rem; color: var(--muted); font-weight: 600; }
.wallboard-card.tone-warning .wallboard-card-value { color: var(--warning); }
.wallboard-card.tone-success .wallboard-card-value { color: var(--success); }
.wallboard-card.tone-info .wallboard-card-value { color: var(--info); }

.wallboard-panel {
  background: var(--card);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 22px 24px;
}
.wallboard-panel h2 { margin-top: 0; }

/* ---------- Emergencia en directo ("botón de pánico") ---------- */
/* Mismo bloque en dashboard y wallboard: rojo, con un pulso sutil (sombra,
   no parpadeo brusco de color) para que sea imposible no verlo sin resultar
   molesto en una pantalla que puede estar horas encendida. */
.emergency-banner {
  background: var(--danger-soft);
  border: 2px solid var(--danger);
  animation: emergency-pulse 1.8s ease-in-out infinite;
}
.emergency-banner-title { font-weight: 800; color: var(--danger); font-size: 1.05rem; margin-bottom: 8px; }
.emergency-banner-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 0;
  border-top: 1px solid rgba(217, 45, 32, 0.2);
}
.emergency-banner-row:first-of-type { border-top: none; }
.emergency-banner-row a { color: var(--danger); font-weight: 700; text-decoration: none; }
.emergency-banner-row a:hover { text-decoration: underline; }
.emergency-banner-age { font-family: "SF Mono", "Consolas", monospace; font-weight: 700; color: var(--danger); }
@keyframes emergency-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(217, 45, 32, 0.32); }
  50% { box-shadow: 0 0 0 8px rgba(217, 45, 32, 0); }
}
.wallboard .emergency-banner { margin-bottom: 24px; padding: 20px 26px; }
.wallboard .emergency-banner-title { font-size: 1.4rem; }
.wallboard .emergency-banner-row { font-size: 1.15rem; }

/* ---------- Cartel de QR por sala ---------- */
.qr-poster-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 24px;
  margin-top: 20px;
}
.qr-poster-item {
  text-align: center;
  padding: 20px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
}
.qr-box {
  display: inline-block;
  background: #fff;
  padding: 12px;
  border-radius: 8px;
}
.qr-poster-label { margin-top: 14px; font-weight: 700; font-size: 1.05rem; }
.qr-poster-label-danger { color: var(--danger); }

/* Al imprimir, solo se ve el cartel en sí (los botones/inputs de esta
   página no tienen sentido en papel). */
@media print {
  .sidebar, .topbar, .no-print, #top-loading-bar, .modal-overlay, .nav-backdrop { display: none !important; }
  .qr-poster-item { break-inside: avoid; }
  .app-shell { display: block !important; }
  main { max-width: none !important; padding: 0 !important; }
}

/* ---------- Mapa de salas ---------- */
.salas-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 16px;
}
.sala-card {
  display: block;
  background: var(--card);
  border: 1px solid var(--border-soft);
  border-left: 5px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 18px 20px;
  text-decoration: none;
  color: var(--text);
  transition: transform 0.1s ease;
}
.sala-card:hover { transform: translateY(-2px); }
.sala-card.tone-success { border-left-color: var(--success); }
.sala-card.tone-warning { border-left-color: var(--warning); background: var(--warning-soft); }
.sala-card.tone-danger { border-left-color: var(--danger); background: var(--danger-soft); animation: emergency-pulse 1.8s ease-in-out infinite; }
.sala-card-emergency-tag { color: var(--danger); font-weight: 800; font-size: 0.85rem; margin-bottom: 6px; }
.sala-card-name { font-weight: 700; font-size: 1.1rem; margin-bottom: 12px; }
.sala-card-metrics { display: flex; gap: 14px; }
.sala-card-metric-value { font-size: 1.6rem; font-weight: 800; line-height: 1; }
.sala-card-metric-label { font-size: 0.72rem; color: var(--muted); margin-top: 4px; }
.sala-card-footer { margin-top: 12px; font-size: 0.78rem; color: var(--muted); }

/* ---------- Salud de red ---------- */
.health-card {
  background: var(--card);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 18px 20px;
}
.health-card-name { font-weight: 700; font-size: 1.05rem; margin-bottom: 2px; }
.health-card-city { font-size: 0.8rem; color: var(--muted); margin-bottom: 12px; }
.health-card-metrics { display: flex; gap: 18px; }
.health-metric-value { font-size: 1.5rem; font-weight: 800; line-height: 1; }
.health-metric-value.online { color: var(--success); }
.health-metric-value.offline { color: var(--danger); }
.health-metric-value.other { color: var(--muted); }
.health-metric-label { font-size: 0.72rem; color: var(--muted); margin-top: 4px; }
.health-summary-row { display: flex; gap: 24px; margin-bottom: 18px; flex-wrap: wrap; }

/* Banner de "local entero caído" (mismo lenguaje visual que
   .emergency-banner: rojo + pulso sutil, para que no se pueda pasar por
   alto sin resultar molesto en pantallas encendidas todo el día). */
.health-local-down-banner { margin-bottom: 14px; }

/* Detalle por dispositivo: árbol local > ubicación física > dispositivo,
   reutilizado también para el diagrama simple de red (misma info: a qué
   se conecta cada dispositivo, agrupado por dónde está instalado). */
.health-detail-section { margin-top: 32px; }
.health-detail-section h2 { margin-bottom: 4px; }
.health-tree-local { background: var(--card); border: 1px solid var(--border-soft); border-radius: var(--radius); padding: 16px 20px; margin-bottom: 16px; }
.health-tree-local-name { font-weight: 700; font-size: 1rem; margin-bottom: 10px; }
.health-tree-site { margin-left: 4px; margin-bottom: 12px; padding-left: 14px; border-left: 2px solid var(--border-soft); }
.health-tree-site:last-child { margin-bottom: 0; }
.health-tree-site-name { font-size: 0.72rem; color: var(--muted); font-weight: 700; margin-bottom: 6px; text-transform: uppercase; letter-spacing: 0.03em; }
.health-tree-device {
  display: grid;
  grid-template-columns: 16px 20px minmax(90px, 200px) 1fr minmax(120px, 240px) auto;
  align-items: center;
  gap: 10px;
  padding: 4px 0;
  font-size: 0.86rem;
}
.health-tree-device-type { flex-shrink: 0; font-size: 0.95rem; text-align: center; }
.health-tree-device-name, .health-tree-device-meta, .health-tree-device-conn {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.health-tree-device-dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; position: relative; top: 1px; }
.health-tree-device-dot.online { background: var(--success); }
.health-tree-device-dot.offline { background: var(--danger); box-shadow: 0 0 0 3px var(--danger-soft); }
.health-tree-device-name { font-weight: 600; }
.health-tree-device-meta { color: var(--muted); font-size: 0.8rem; }
.health-tree-device-conn { color: var(--muted); font-size: 0.78rem; font-family: "SF Mono", "Consolas", monospace; }
.health-tree-device-actions { display: flex; gap: 6px; flex-wrap: nowrap; justify-self: end; }
.health-tree-btn { padding: 2px 8px; font-size: 0.75rem; }

/* ---------- Mapa de España (esquemático) ---------- */
/* Mapa de calles de verdad (Leaflet + teselas de CARTO), no un contorno de
   España dibujado a mano: Leaflet necesita un contenedor con altura fija en
   píxeles, por eso aquí no se usa aspect-ratio. */
.spain-map {
  position: relative;
  width: 100%;
  height: 520px;
  background: var(--bg-soft, var(--bg));
  border-radius: var(--radius);
  overflow: hidden;
  z-index: 0;
}
.city-pin-dot {
  position: relative;
  display: block;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 3px solid var(--card);
  box-shadow: 0 1px 4px rgba(0,0,0,.35);
  cursor: pointer;
}
.city-pin-dot.tone-success { background: var(--success); }
.city-pin-dot.tone-warning { background: var(--warning); }
.city-pin-dot.tone-danger { background: var(--danger); animation: emergency-pulse 1.8s ease-in-out infinite; }
.city-pin-dot.selected { outline: 2px solid var(--primary); outline-offset: 2px; }

/* Marca aparte (no es un color de "estado") para indicar qué locales ya
   tienen infraestructura de red (UniFi) desplegada, del total de 38 en los
   que el grupo tiene salas: el despliegue va local por local, así que el
   color del pin (que va de los tickets) no puede confundirse con esto. */
.city-pin-infra-mark {
  position: absolute;
  top: -3px;
  right: -3px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--info);
  border: 1.5px solid var(--card);
}
.city-pin-label-tooltip {
  font-size: 0.72rem;
  font-weight: 700;
  background: var(--card) !important;
  color: var(--text);
  padding: 2px 7px;
  border-radius: 10px;
  border: 1px solid var(--border-soft) !important;
  white-space: nowrap;
  box-shadow: none !important;
}
.city-pin-label-tooltip::before { display: none; }
.map-legend { display: flex; gap: 18px; margin-top: 14px; font-size: 0.8rem; color: var(--muted); flex-wrap: wrap; }
.map-legend-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 5px; vertical-align: middle; }
.map-legend-dot.tone-success { background: var(--success); }
.map-legend-dot.tone-warning { background: var(--warning); }
.map-legend-dot.tone-danger { background: var(--danger); }

.local-row { padding: 12px 0; border-bottom: 1px solid var(--border-soft); display: flex; gap: 12px; align-items: flex-start; }
.local-row:last-child { border-bottom: none; }
.local-row-dot { width: 12px; height: 12px; border-radius: 50%; margin-top: 4px; flex-shrink: 0; }
.local-row-dot.tone-success { background: var(--success); }
.local-row-dot.tone-warning { background: var(--warning); }
.local-row-dot.tone-danger { background: var(--danger); }
.local-row-dot.tone-info { background: var(--info); }
.local-row-dot.tone-neutral { background: var(--border-soft); }
.local-row-address { font-weight: 700; font-size: 0.92rem; }
.local-row-experiences { font-size: 0.82rem; color: var(--muted); margin-top: 2px; }
.local-row-count { font-size: 0.78rem; color: var(--muted); margin-top: 4px; }

/* La oficina central del grupo, mostrada aparte del listado de salas (no es
   una sala de escape, es la sede): un poco separada visualmente para que no
   se confunda con una más de la lista. */
.local-row-oficina { margin-top: 4px; padding-top: 16px; border-top: 1px dashed var(--border-soft); }
.local-row-tag {
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--muted);
  background: var(--bg-soft, var(--bg));
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  padding: 1px 6px;
  vertical-align: middle;
  margin-left: 4px;
}

/* Filtro de sala aplicado desde el mapa de salas o desde un QR: se muestra
   como un chip que se puede quitar, en vez de un desplegable más para algo
   que no se usa siempre. */
.sala-filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--primary-soft);
  color: var(--primary);
  border-radius: 999px;
  padding: 6px 8px 6px 14px;
  font-weight: 600;
  font-size: 0.85rem;
}
.sala-filter-chip button {
  background: none;
  border: none;
  color: inherit;
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  padding: 2px 6px;
  margin: 0;
}
.sala-filter-chip button:hover { background: rgba(0,0,0,0.08); border-radius: 50%; }

/* ---------- Mapa de salas: buscador + pines por local + panel de lista ---------- */
/* Cuadro de búsqueda de texto libre por ciudad/dirección/experiencia (junto
   al selector de área que ya existía), en la cabecera de la página. */
.salas-header-controls {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.salas-header-controls input[type="search"] { width: auto; min-width: 240px; margin: 0; }
.salas-header-controls select { width: auto; margin: 0; }

/* Mapa a la izquierda + panel de lista de locales a la derecha (vista
   combinada lista+mapa), mismo patrón de grid que .ticket-detail-grid: se
   apila en una sola columna en pantallas estrechas. */
.salas-map-grid {
  display: grid;
  grid-template-columns: 1.7fr 1fr;
  gap: 20px;
  align-items: start;
}
@media (max-width: 900px) {
  .salas-map-grid { grid-template-columns: 1fr; }
}

.salas-list-panel { display: flex; flex-direction: column; max-height: 560px; }
.salas-list-panel-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}
.salas-list-panel-header h2 { margin: 0; flex-shrink: 0; }
.salas-list-panel-header #salas-list-count { flex: 1; }
.salas-list-panel-header button { margin: 0; padding: 6px 12px; font-size: 0.8rem; flex-shrink: 0; }
.salas-list-panel.collapsed .salas-list { display: none; }
.salas-list { overflow-y: auto; flex: 1; }

.salas-list-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-bottom: 1px solid var(--border-soft);
  border-radius: 0;
  padding: 10px 4px;
  margin: 0;
  cursor: pointer;
  color: var(--text);
  box-shadow: none;
}
.salas-list-item:last-child { border-bottom: none; }
.salas-list-item:hover { background: var(--bg-soft, var(--bg)); box-shadow: none; }
.salas-list-item.selected { background: var(--primary-soft); }
.salas-list-item .local-row-dot { margin-top: 5px; }
.salas-list-item-text { min-width: 0; }
.salas-list-item-title { font-weight: 700; font-size: 0.88rem; display: block; }
.salas-list-item-address { font-size: 0.78rem; color: var(--muted); display: block; margin-top: 1px; }

/* Pin de LOCAL (no de ciudad): un punto más pequeño que el de ciudad, en las
   coordenadas exactas del local cuando ya se ha geocodificado. Reutiliza los
   mismos tonos (tone-success/warning/danger) que ya existían para ciudades. */
.local-pin-dot {
  position: relative;
  display: block;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  border: 2px solid var(--card);
  box-shadow: 0 1px 3px rgba(0,0,0,.35);
  cursor: pointer;
}
.local-pin-dot.tone-success { background: var(--success); }
.local-pin-dot.tone-warning { background: var(--warning); }
.local-pin-dot.tone-danger { background: var(--danger); animation: emergency-pulse 1.8s ease-in-out infinite; }
.local-pin-dot.selected { outline: 2px solid var(--primary); outline-offset: 2px; }
.local-pin-dot.dimmed { opacity: 0.3; }

/* Marca de infraestructura por LOCAL con estado en vivo (online/offline),
   ampliando el patrón booleano de ".city-pin-infra-mark": aquí el color
   depende del estado real del dispositivo emparejado, no solo de si existe
   infraestructura o no. Sin marca cuando no hay dato de red (null). */
.pin-infra-status-mark {
  position: absolute;
  top: -3px;
  right: -3px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1.5px solid var(--card);
}
.pin-infra-status-mark.status-online { background: var(--success); }
.pin-infra-status-mark.status-offline { background: var(--danger); }
.pin-infra-status-mark.status-none { background: var(--muted); opacity: 0.6; }

/* Popup de Leaflet al hacer click en el pin de un local concreto. */
.local-popup { font-size: 0.85rem; }
.local-popup-title { font-weight: 700; margin-bottom: 2px; }
.local-popup-address { color: var(--text-soft); margin-bottom: 4px; }
.local-popup-experiences { color: var(--muted); font-size: 0.78rem; margin-bottom: 4px; }
.local-popup-status { font-size: 0.78rem; color: var(--muted); }
.leaflet-popup-content-wrapper, .leaflet-popup-tip { background: var(--card); color: var(--text); }

/* ---------- Inicio (pantalla de aterrizaje tras iniciar sesión) ---------- */

.inicio-hero {
  text-align: center;
  margin: 18px 0 32px;
}
.inicio-hero h1 { font-size: 1.7rem; }
.inicio-hero .page-subtitle { margin: 0; }

.inicio-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
  max-width: 920px;
  margin: 0 auto;
}

.inicio-tile {
  background: var(--card);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: 26px 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 10px;
  color: var(--text);
  text-decoration: none;
  transition: transform 0.15s, border-color 0.15s, box-shadow 0.15s;
  animation: fade-up 0.35s ease both;
}
.inicio-tile:hover {
  transform: translateY(-3px);
  border-color: var(--primary);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);
}
.inicio-tile-icon {
  width: 52px;
  height: 52px;
  border-radius: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--primary-soft);
  color: var(--primary);
}
.inicio-tile-icon svg { width: 26px; height: 26px; }
.inicio-tile-label { font-weight: 700; font-size: 1rem; }
.inicio-tile-desc { color: var(--muted); font-size: 0.8rem; line-height: 1.3; }

@media (max-width: 600px) {
  .inicio-grid { grid-template-columns: repeat(2, 1fr); }
}

.hint-text {
  color: var(--muted);
  font-size: 0.8rem;
  line-height: 1.3;
}

/* Miniaturas de capturas pegadas (Ctrl+V) o arrastradas al cuadro de
   comentario de un ticket, antes de enviarlas (ver public/js/ticket.js).
   Un solo bloque de estilos reutilizable, no hace falta nada por tipo de
   fichero: si no es una imagen, se muestra un icono genérico igual. */
.pasted-attachments-preview {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 8px 0;
}
.pasted-attachments-preview:empty { display: none; }
.pasted-attachment-chip {
  position: relative;
  width: 64px;
  height: 64px;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--surface-2, #f2f2f5);
}
.pasted-attachment-chip img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.pasted-attachment-chip .pasted-attachment-name {
  position: absolute;
  inset: auto 0 0 0;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-size: 0.6rem;
  padding: 2px 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pasted-attachment-chip .pasted-attachment-remove {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: none;
  background: rgba(0, 0, 0, 0.65);
  color: #fff;
  font-size: 0.75rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}
.pasted-attachment-chip .pasted-attachment-remove:hover { background: var(--danger); }
.comment-dropzone-active {
  outline: 2px dashed var(--primary);
  outline-offset: 2px;
}

/* Checklist de ejecución de altas/bajas de empleado (ver public/js/ticket.js: renderChecklist).
   Cada paso se decide con dos botones (Sí/No), no una casilla suelta: así
   queda explícito si a esta persona en concreto le hacía falta ese paso o
   no, en vez de que "sin marcar" pueda significar dos cosas distintas
   (pendiente de revisar, o no le aplica). */
.checklist-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.checklist-item {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 6px;
  border-radius: 8px;
}
.checklist-item-text { display: flex; flex-direction: column; gap: 2px; }
.checklist-item-label { font-size: 0.92rem; }
.checklist-item-yes .checklist-item-label { color: var(--muted); text-decoration: line-through; }
.checklist-item-no .checklist-item-label { color: var(--muted); }
.checklist-item-meta { font-size: 0.76rem; color: var(--muted); }
.checklist-item-actions { display: flex; gap: 6px; flex-shrink: 0; }
.checklist-btn {
  padding: 4px 12px;
  margin-top: 0;
  font-size: 0.82rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text);
  box-shadow: none;
}
.checklist-btn:hover { background: var(--border-soft); box-shadow: none; }
.checklist-btn-yes.active { background: var(--success); border-color: var(--success); color: #fff; }
.checklist-btn-yes.active:hover { background: var(--success); }
.checklist-btn-no.active { background: var(--danger); border-color: var(--danger); color: #fff; }
.checklist-btn-no.active:hover { background: var(--danger); }

/* Mapa de incidencias (heatmap) */
.heatmap-scroll { overflow-x: auto; margin-top: 16px; }
.heatmap-table { border-collapse: collapse; width: 100%; font-size: 13px; }
.heatmap-table th, .heatmap-table td { padding: 6px 10px; text-align: center; white-space: nowrap; }
.heatmap-table thead th { border-bottom: 2px solid var(--border-color, #ddd); font-weight: 600; }
.heatmap-sala { text-align: left; font-weight: 600; position: sticky; left: 0; background: var(--card, #fff); }
.heatmap-total { font-weight: 700; }
.heatmap-cell { border: 1px solid rgba(0,0,0,0.05); border-radius: 4px; font-variant-numeric: tabular-nums; }

/* Cementerio de piezas */
.cementerio-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 16px; margin-top: 16px; }
.cementerio-card { background: var(--card, #fff); border: 1px solid var(--border-color, #ddd); border-radius: 8px; padding: 16px; display: flex; flex-direction: column; gap: 8px; }
.cementerio-card-header { display: flex; justify-content: space-between; align-items: baseline; font-size: 12px; color: var(--muted-color, #777); text-transform: uppercase; letter-spacing: .03em; }
.cementerio-title { font-weight: 600; }
.cementerio-lapida { font-style: italic; border-left: 3px solid var(--border-color, #ddd); padding-left: 10px; color: var(--muted-color, #555); }
.cementerio-link { font-size: 13px; margin-top: 4px; }

/* Capsula del tiempo */
#capsula-form-card { max-width: 480px; }
#capsula-form-card label { display: block; margin-top: 10px; margin-bottom: 4px; font-weight: 600; font-size: 13px; }
#capsula-form-card input[type="text"], #capsula-form-card textarea { width: 100%; box-sizing: border-box; }
.capsula-timeline { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; margin-top: 16px; }
.capsula-item { background: var(--card, #fff); border: 1px solid var(--border-color, #ddd); border-radius: 8px; overflow: hidden; display: flex; flex-direction: column; }
.capsula-item img { width: 100%; aspect-ratio: 4/3; object-fit: cover; display: block; }
.capsula-item-body { padding: 10px 12px; display: flex; flex-direction: column; gap: 4px; }
.capsula-item-fecha { font-size: 12px; color: var(--muted-color, #777); }
.capsula-item-nota { margin: 0; font-size: 14px; }
.capsula-item-autor { font-size: 12px; color: var(--muted-color, #777); font-style: italic; }

/* Oraculo de los viernes */
.oraculo-text {
  margin: 16px 0;
  padding: 14px 18px;
  border-left: 3px solid var(--border-color, #ddd);
  background: var(--row-hover, #f8faff);
  border-radius: 8px;
  font-style: italic;
  line-height: 1.5;
}
.oraculo-send-block { margin-top: 18px; }
.oraculo-send-label { margin: 0 0 8px 0; }
.oraculo-recipients {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  margin-bottom: 12px;
}
.oraculo-recipient { display: flex; align-items: center; gap: 6px; }
.oraculo-send-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 8px;
}
