:root {                 /* tema oscuro (por defecto) */
  --bg: #0d1117;
  --panel: #161b22;
  --input-bg: #0b0f14;
  --btn-bg: #21262d;
  --border: #30363d;
  --fg: #e6edf3;
  --muted: #9da7b3;
  --accent: #2f81f7;
  --accent-on: #1f6feb;
}
:root[data-theme="light"] {   /* tema claro */
  --bg: #f6f8fa;
  --panel: #ffffff;
  --input-bg: #ffffff;
  --btn-bg: #f0f2f5;
  --border: #d0d7de;
  --fg: #1f2328;
  --muted: #59636e;
  --accent: #2f81f7;
  --accent-on: #1f6feb;
}
* { box-sizing: border-box; }
/* El atributo `hidden` debe ganar SIEMPRE, aunque el elemento tenga
   display:flex/grid en su regla (si no, #viewer y .osk se muestran solos). */
[hidden] { display: none !important; }
html, body { margin: 0; height: 100%; background: var(--bg); color: var(--fg);
  font-family: system-ui, sans-serif; -webkit-user-select: none; user-select: none; }

/* --- Pantalla de conexión --- */
.panel { width: calc(100% - 2rem); max-width: 360px; margin: 12dvh auto; padding: 24px;
  background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
  display: grid; gap: 14px; }
.panel h1 { margin: 0; font-size: 1.5rem; text-align: center; }
.panel label { display: grid; gap: 6px; font-size: .85rem; color: var(--muted); }
.panel input, button { font: inherit; }
input[type=password], input[type=text] { padding: 10px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--input-bg); color: var(--fg); }
.status { min-height: 1.2em; text-align: center; color: var(--muted); font-size: .85rem; }
.panel label small { color: var(--muted); font-weight: normal; }
/* Botón "Olvidar este dispositivo": discreto, tipo enlace. */
.linkish { background: none; border: none; color: var(--muted); font-size: .8rem;
  text-decoration: underline; padding: 2px; cursor: pointer; }
.linkish:hover { color: var(--accent); border: none; }
#btn-connect:disabled { opacity: .5; cursor: not-allowed; }

button { padding: 8px 12px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--btn-bg); color: var(--fg); cursor: pointer; }
.theme-toggle { padding: 6px 10px; }
button:hover { border-color: var(--accent); }
button.active { background: var(--accent-on); border-color: var(--accent); color: #fff; }
#btn-connect { background: var(--accent-on); border-color: var(--accent); color: #fff; padding: 10px; }

/* --- Vista remota --- */
#viewer { position: fixed; inset: 0; height: 100dvh; overflow: hidden;
  display: flex; flex-direction: column; }
/* toolbar y osk no se encogen; el stage (flex:1) absorbe el resto. */
#toolbar { display: flex; gap: 8px; align-items: center; padding: 6px 10px;
  background: var(--panel); border-bottom: 1px solid var(--border);
  flex-wrap: nowrap; overflow-x: auto; flex-shrink: 0; }
#toolbar .group { display: flex; gap: 4px; flex-shrink: 0; }
#toolbar button { flex-shrink: 0; white-space: nowrap; }
#toolbar .group button { padding: 6px 10px; }

/* El stage es el área de video; el <video> se ENCAJA a cualquier pantalla. */
/* min-height/min-width: 0 permiten que el stage se encoja al espacio disponible
   (si no, crece al tamaño nativo del video y este se sale de la pantalla). */
/* position:relative + video en absoluto = el video se ajusta SIEMPRE al stage,
   sin importar su resolución nativa (antes tomaba 1280x720 y desbordaba). */
#stage { position: relative; flex: 1; min-height: 0; min-width: 0;
  overflow: hidden; background: #000; touch-action: none; }
#remote { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; transform-origin: center center; touch-action: none;
  -webkit-touch-callout: none; }
/* En móvil los gestos los maneja #stage; el <video> NO recibe eventos → el navegador
   no muestra su menú de long-press (copiar fotograma / picture-in-picture). En laptop
   sí los recibe (el mouse controla sobre el video). */
html.touch #remote { pointer-events: none; }
/* Suavizado OFF: escalado nítido pixel-perfect (útil para texto pequeño al ampliar). */
#remote.pixelated { image-rendering: pixelated; }

/* Botón Desconectar: acento de peligro para distinguirlo del resto. */
#btn-disconnect { color: #f85149; border-color: #f85149; }
#btn-disconnect:hover { background: #f85149; color: #fff; border-color: #f85149; }

/* --- Modo inmersivo (laptop, estilo AnyDesk) --- */
/* La toolbar se autooculta (se ve solo la pantalla remota, ajustada a toda la
   pantalla) y reaparece al llevar el mouse al borde SUPERIOR. */
#reveal-zone { display: none; }
#viewer.immersive #toolbar {
  position: absolute; left: 0; right: 0; top: 0; z-index: 10;
  transform: translateY(-100%); transition: transform .18s ease; }
#viewer.immersive.reveal #toolbar { transform: translateY(0); }
#viewer.immersive #reveal-zone {           /* franja sensible arriba para reaparecer */
  display: block; position: absolute; top: 0; left: 0; right: 0; height: 6px; z-index: 11; }

/* --- Teclado MÓVIL estilo RVNC Viewer: barra de teclas especiales (scroll
   HORIZONTAL) + input oculto que abre el teclado nativo. En FLUJO dentro de la
   columna: el #stage (flex:1) se encoge para dejarle sitio y, con el viewport
   redimensionado (interactive-widget), el video se ve completo sobre el teclado
   en vez de quedar cortado. --- */
#mobilekb { position: relative; flex-shrink: 0; border-top: 1px solid var(--border);
  background: var(--panel); }
#special-bar { display: flex; gap: 6px; padding: 6px 8px;
  overflow-x: auto; overflow-y: hidden; white-space: nowrap;
  background: var(--panel); border-bottom: 1px solid var(--border);
  -webkit-overflow-scrolling: touch; scrollbar-width: thin; }
#special-bar button { flex: 0 0 auto; padding: 12px 14px; min-width: 46px; }  /* táctil */
#special-bar [data-mod].active { background: var(--accent-on); border-color: var(--accent); color: #fff; }
/* Campo de texto VISIBLE (una línea con scroll horizontal), SIEMPRE abajo. Tocarlo
   abre el teclado nativo; lo tecleado se refleja en el host. */
#text-entry { display: block; width: 100%; box-sizing: border-box;
  padding: 10px 12px; font-size: 16px;                   /* 16px evita zoom iOS */
  background: var(--input-bg); color: var(--fg); border: 0;
  resize: none; white-space: pre; overflow-x: auto; overflow-y: hidden;
  line-height: 1.3; height: calc(1.3em + 20px); }

/* Círculo de aviso del arrastre por long-press (móvil). Se posiciona con JS a la
   posición del dedo (coords de viewport → position:fixed). */
#drag-ripple { position: fixed; width: 44px; height: 44px; margin: -22px 0 0 -22px;
  border-radius: 50%; border: 2px solid var(--accent);
  background: rgba(47, 129, 247, .22); pointer-events: none; z-index: 30; display: none; }

/* Controles solo para celular (táctil): en laptop hay mouse/teclado a mano. */
html:not(.touch) .touch-only { display: none; }
/* Controles solo para laptop: en móvil viven en la barra de teclas especiales.
   !important para ganar a `#toolbar .group { display:flex }` (más específico por el id). */
html.touch .desktop-only { display: none !important; }

/* Cursor VIRTUAL (solo móvil): indica dónde está el puntero del host cuando no se ve
   en el stream (modo trackpad / con zoom). Position:fixed → se coloca en coords de
   viewport con JS; una flecha simple para no taparlo con un punto grande. */
/* Cursor virtual DESHABILITADO por preferencia del usuario (estorbaba). Se deja el
   elemento y el estilo por si se quiere reactivar: bastaría `html.touch #cursor-dot
   { display:block }`. Mientras, queda oculto siempre. */
#cursor-dot { display: none !important; position: fixed; left: 0; top: 0; z-index: 25;
  width: 0; height: 0; pointer-events: none; opacity: 0; transition: opacity .25s ease;
  border-left: 6px solid transparent; border-right: 6px solid transparent;
  border-top: 11px solid rgba(255, 255, 255, .82); transform: translate(-1px, -1px) rotate(-35deg);
  transform-origin: top left; filter: drop-shadow(0 0 1px #000); }
#cursor-dot.show { opacity: 1; }

/* Franja de scroll (móvil): barra en el borde derecho. Se arrastra para desplazar; el
   resto del stage sigue moviendo el cursor (no interfiere). touch-action:none = sin
   scroll de página. Solo se ve en táctil y cuando el botón ⇅ Scroll la activa. */
#scroll-strip { position: absolute; top: 12%; bottom: 12%; right: 6px; width: 34px;
  z-index: 26; display: flex; align-items: center; justify-content: center;
  border-radius: 17px; background: #0009; color: #fff; font-size: 1.1rem;
  border: 1px solid #ffffff44; touch-action: none; -webkit-user-select: none; user-select: none;
  box-shadow: 0 2px 10px #0007; overflow: hidden; }
#scroll-strip.dragging { background: var(--accent-on); border-color: var(--accent); }
/* Indicador animado de dirección: una flecha que se desliza en el sentido del scroll
   (arriba/abajo) mientras la franja está desplazada, para ver que se está moviendo. */
#scroll-strip.up::after, #scroll-strip.down::after { content: "▲"; font-size: 1.2rem; line-height: 1; }
#scroll-strip.up::after { animation: scrollUp .5s linear infinite; }
#scroll-strip.down::after { content: "▼"; animation: scrollDown .5s linear infinite; }
/* Oculta el glifo base "⇕" mientras anima (el ::after fija su propio tamaño). */
#scroll-strip.up, #scroll-strip.down { font-size: 0; }
@keyframes scrollUp   { from { transform: translateY(60%); opacity: .2; } to { transform: translateY(-60%); opacity: 1; } }
@keyframes scrollDown { from { transform: translateY(-60%); opacity: .2; } to { transform: translateY(60%); opacity: 1; } }

/* Aviso de reconexión: banda centrada arriba, sobre el video (no bloquea el toque). */
#reconnect-overlay { position: absolute; top: 12px; left: 50%; transform: translateX(-50%);
  z-index: 40; padding: 8px 16px; border-radius: 999px; pointer-events: none;
  background: #000c; color: #fff; font-size: .9rem; box-shadow: 0 4px 16px #0007; }

/* Tooltip por long-press (móvil): burbuja con la descripción del botón. */
#tooltip { position: fixed; z-index: 60; max-width: 70vw; padding: 8px 12px;
  background: #000d; color: #fff; border-radius: 8px; font-size: .85rem;
  line-height: 1.25; pointer-events: none; box-shadow: 0 4px 16px #0008;
  white-space: normal; }

@media (max-width: 640px) { .panel { padding: 18px; } }

/* ── Atajos personalizados (remapeo de teclas, Fase 6) ────────────────── */
#special-bar .custom-key { background: var(--accent-on); border-color: var(--accent); color: #fff; }
.modal { position: fixed; inset: 0; z-index: 80; display: flex;
  align-items: center; justify-content: center; padding: 16px;
  background: rgba(0, 0, 0, .5); }
.modal[hidden] { display: none; }
.modal-box { background: var(--panel); border: 1px solid var(--border);
  border-radius: 14px; padding: 18px; width: min(420px, 100%);
  max-height: 90vh; overflow-y: auto; box-shadow: 0 12px 40px rgba(0, 0, 0, .4); }
.modal-box h2 { margin: 0 0 4px; font-size: 1.1rem; }
.km-desc { margin: 0 0 12px; color: var(--muted); font-size: .85rem; }
.km-mods { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; }
.km-mods label { flex-direction: row; align-items: center; gap: 6px; font-size: .9rem; color: var(--fg); }
.km-row { display: flex; gap: 10px; align-items: flex-end; margin-bottom: 12px; flex-wrap: wrap; }
.modal-box label { display: flex; flex-direction: column; gap: 4px;
  font-size: .85rem; color: var(--muted); margin-bottom: 10px; }
.modal-box input[type="text"], .modal-box select { padding: 8px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--input-bg); color: var(--fg); }
#km-key { width: 60px; text-align: center; }
.km-msg { color: var(--accent); font-size: .82rem; }
.km-list { margin: 6px 0 14px; display: flex; flex-direction: column; gap: 6px;
  color: var(--muted); font-size: .9rem; }
.km-item { display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 8px 10px; border: 1px solid var(--border);
  border-radius: 8px; color: var(--fg); }
.modal-box .primary { background: var(--accent-on); border-color: var(--accent); color: #fff; }
.danger { background: #b42318; border-color: #b42318; color: #fff; }
button.sm { padding: 6px 10px; font-size: .82rem; }

/* Botón de captura de teclado en estado "Parcial": se QUIERE capturar pero el
   navegador no deja (falta pantalla completa, F11, sin HTTPS o no es Chromium). */
button.warn { background: var(--warn-bg, #7a4b00); border-color: #d08700; color: #fff; }

/* Aviso breve sobre el video: explica en una línea por qué el teclado no se
   captura, sin robar el foco ni bloquear el uso. */
#toast {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%);
  z-index: 60; max-width: min(90vw, 560px);
  padding: 10px 14px; border-radius: 10px;
  background: rgba(0, 0, 0, .82); color: #fff;
  font-size: 14px; line-height: 1.35; text-align: center;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .35);
  pointer-events: none;
}

/* Aviso persistente del teclado: mientras la captura NO esté activa, se queda a
   la vista (con el motivo) en vez de dejar al usuario creyendo que DualCast no
   lee las combinaciones. Va sobre el video, arriba del #toast. */
#kb-hint {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%);
  z-index: 61; max-width: min(94vw, 680px);
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: 12px;
  background: rgba(122, 75, 0, .96); border: 1px solid #d08700; color: #fff;
  font-size: 14px; line-height: 1.35;
  box-shadow: 0 8px 28px rgba(0, 0, 0, .4);
}
#kb-hint[hidden] { display: none; }
#kb-hint button { flex-shrink: 0; }
#kb-hint #kb-hint-fix { background: #fff; color: #7a4b00; border-color: #fff; font-weight: 600; }
#kb-hint #kb-hint-close { background: transparent; border-color: transparent; color: #fff; }
/* Con el aviso a la vista, el #toast sube para no taparlo. */
body.kb-hint-on #toast { bottom: 84px; }
