:root {
  --menussh-radius: .75rem;
  --sidebar-w: 250px;
  --sidebar-w-collapsed: 68px;
}

/* --- modal de "test de conexion" (Credenciales y Servidores) --- */

.test-modal-icon {
  width: 64px;
  height: 64px;
  margin: 0 auto;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background-color .2s ease, color .2s ease;
}

.test-modal-icon-loading {
  background: var(--bs-primary-bg-subtle, rgba(13, 110, 253, .12));
  color: var(--bs-primary);
}

.test-modal-icon-ok {
  background: var(--bs-success-bg-subtle, rgba(25, 135, 84, .12));
  color: var(--bs-success);
  animation: test-modal-pop .35s cubic-bezier(.34, 1.56, .64, 1);
}

.test-modal-icon-fail {
  background: var(--bs-danger-bg-subtle, rgba(220, 53, 69, .12));
  color: var(--bs-danger);
  animation: test-modal-pop .35s cubic-bezier(.34, 1.56, .64, 1);
}

/* archivo subido OK, pero no parece la clave privada esperada (subieron
   la .pub, un .ppk de PuTTY, o algo irreconocible) -- ni exito pleno ni
   fallo (el archivo SI se guardo), un tercer estado a medio camino. */
.test-modal-icon-warning {
  background: var(--bs-warning-bg-subtle, rgba(255, 193, 7, .15));
  color: var(--bs-warning-text-emphasis, #a17400);
  animation: test-modal-pop .35s cubic-bezier(.34, 1.56, .64, 1);
}

.test-modal-row.text-warning-row dd {
  color: var(--bs-warning-text-emphasis, #a17400);
  font-weight: 600;
}

.test-modal-icon svg {
  width: 30px;
  height: 30px;
}

.test-modal-spinner {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 3px solid rgba(13, 110, 253, .25);
  border-top-color: var(--bs-primary);
  animation: test-modal-spin .7s linear infinite;
}

@keyframes test-modal-spin {
  to { transform: rotate(360deg); }
}

@keyframes test-modal-pop {
  0% { transform: scale(.4); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}

.test-modal-details {
  width: 100%;
  max-width: 340px;
}

.test-modal-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: .4rem 0;
  border-bottom: 1px solid var(--bs-border-color-translucent, rgba(127, 127, 127, .15));
  font-size: .9rem;
}

.test-modal-row:last-child {
  border-bottom: none;
}

.test-modal-row dt {
  flex: 0 0 auto;
  color: var(--bs-secondary-color);
  font-weight: 500;
}

.test-modal-row dd {
  margin: 0;
  text-align: right;
  word-break: break-word;
}

/* --- seccion de "clave privada" dentro del form de Credenciales --- */

.uts-key-section {
  padding: 1rem 1rem .25rem;
  border: 1px solid var(--bs-border-color);
  border-radius: var(--menussh-radius);
  background: var(--bs-tertiary-bg);
}

.uts-key-section-title {
  letter-spacing: .05em;
  font-weight: 600;
}

/* password sugerida oculta por defecto en el listado de Credenciales,
   con un ojito para revelarla fila por fila (ver macros.password_reveal). */
.pw-reveal {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
}

.pw-reveal-mask {
  letter-spacing: .15em;
}

.toggle-password-reveal {
  color: var(--bs-secondary-color);
  line-height: 1;
}

.toggle-password-reveal:hover {
  color: var(--bs-body-color);
}

/* --- sidebar principal (reemplaza la vieja navbar de arriba) --- */

.sidebar {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: var(--sidebar-w);
  background: #1a1d21;
  color: #cfd3d8;
  z-index: 1045;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  transition: width .2s ease, transform .2s ease;
}

html[data-sidebar="collapsed"] .sidebar {
  width: var(--sidebar-w-collapsed);
}

.sidebar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem .9rem;
  border-bottom: 1px solid rgba(255, 255, 255, .1);
  flex: 0 0 auto;
}

.sidebar-brand {
  display: flex;
  align-items: center;
  gap: .6rem;
  color: #fff;
  text-decoration: none;
  font-weight: 600;
  overflow: hidden;
  white-space: nowrap;
}

.sidebar-brand-mark {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: var(--bs-primary);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .95rem;
}

.sidebar-collapse-btn {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: #9aa0a8;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform .2s ease, background-color .15s ease;
}

.sidebar-collapse-btn:hover {
  background: rgba(255, 255, 255, .08);
  color: #fff;
}

html[data-sidebar="collapsed"] .sidebar-collapse-btn {
  transform: rotate(180deg);
}

.sidebar-nav {
  flex: 1 1 auto;
  padding: .75rem 0;
}

.sidebar-section {
  margin-bottom: .75rem;
}

.sidebar-section-title {
  padding: .5rem 1.1rem .35rem;
  font-size: .7rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: #6c7278;
  white-space: nowrap;
  overflow: hidden;
}

.sidebar-link {
  display: flex;
  align-items: center;
  gap: .8rem;
  padding: .55rem 1.1rem;
  color: #cfd3d8;
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  border-left: 3px solid transparent;
  transition: background-color .12s ease, color .12s ease;
}

.sidebar-link svg {
  flex: 0 0 auto;
}

.sidebar-link:hover {
  background: rgba(255, 255, 255, .06);
  color: #fff;
}

.sidebar-link.active {
  background: rgba(255, 255, 255, .08);
  color: #fff;
  border-left-color: var(--bs-primary);
}

.sidebar-footer {
  flex: 0 0 auto;
  border-top: 1px solid rgba(255, 255, 255, .1);
  padding: .6rem 0;
}

.sidebar-user {
  padding: .4rem 1.1rem;
  font-size: .8rem;
  color: #9aa0a8;
  white-space: nowrap;
  overflow: hidden;
}

/* las etiquetas de texto se ocultan cuando el sidebar esta colapsado a
   "riel" de solo iconos -- title="" en cada link cubre la accesibilidad
   (aparece como tooltip nativo del navegador). */
html[data-sidebar="collapsed"] .sidebar-label {
  display: none;
}

html[data-sidebar="collapsed"] .sidebar-link,
html[data-sidebar="collapsed"] .sidebar-header {
  justify-content: center;
}

.sidebar-mobile-toggle {
  display: none;
  position: fixed;
  top: .75rem;
  left: .75rem;
  z-index: 1050;
  width: 40px;
  height: 40px;
  border-radius: 8px;
  border: 1px solid var(--bs-border-color);
  background: var(--bs-body-bg);
  color: var(--bs-body-color);
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .15);
}

.sidebar-backdrop {
  display: none;
}

.main-content {
  margin-left: var(--sidebar-w);
  padding: 1.5rem 2rem;
  transition: margin-left .2s ease;
}

html[data-sidebar="collapsed"] .main-content {
  margin-left: var(--sidebar-w-collapsed);
}

/* mobile: el sidebar pasa a ser un panel superpuesto oculto por
   default (transform fuera de pantalla) en vez de "riel" -- no hay
   espacio para dejarlo siempre visible, ni colapsado. */
@media (max-width: 991.98px) {
  .sidebar,
  html[data-sidebar="collapsed"] .sidebar {
    width: var(--sidebar-w);
    transform: translateX(-100%);
  }

  body.sidebar-open .sidebar {
    transform: translateX(0);
  }

  .sidebar-collapse-btn {
    display: none;
  }

  .sidebar-mobile-toggle {
    display: flex;
  }

  body.sidebar-open .sidebar-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, .4);
    z-index: 1040;
  }

  .main-content,
  html[data-sidebar="collapsed"] .main-content {
    margin-left: 0;
    padding-top: 4rem;
  }
}

/* toggle de tema: icono chico fijo, disponible en toda la app incluida
   la pantalla de login (antes solo estaba, como texto, en la navbar --
   que no existe para un usuario sin sesion). */
.theme-fab {
  position: fixed;
  right: 1.25rem;
  bottom: 1.25rem;
  z-index: 1040;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--bs-border-color);
  background: var(--bs-body-bg);
  color: var(--bs-body-color);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .15);
  transition: transform .15s ease, box-shadow .15s ease;
}

.theme-fab:hover {
  transform: scale(1.08);
  box-shadow: 0 4px 12px rgba(0, 0, 0, .2);
}

.card {
  border-radius: var(--menussh-radius);
  border: none;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .08);
}

table.table-tools tbody tr {
  transition: background-color .1s ease;
}

table.table-tools thead th {
  /* antes usaba --menussh-navbar-h (alto de la vieja navbar de arriba,
     que ya no existe -- ahora es un sidebar lateral, no hay nada fijo
     arriba del contenido). */
  position: sticky;
  top: 0;
  background: var(--bs-body-bg);
  z-index: 5;
  user-select: none;
  white-space: nowrap;
}

table.table-tools thead th[data-sort] {
  cursor: pointer;
}

table.table-tools thead th[data-sort]:hover {
  background: var(--bs-tertiary-bg);
}

table.table-tools thead th.sorted-asc::after {
  content: " \25B2";
  opacity: .6;
}

table.table-tools thead th.sorted-desc::after {
  content: " \25BC";
  opacity: .6;
}

.table-filter {
  max-width: 320px;
}

.stat-bar-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-bottom: .4rem;
}

.stat-bar-label {
  width: 45%;
  flex: 0 0 45%;
  font-size: .875rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.stat-bar-track {
  flex: 1 1 auto;
  background: var(--bs-tertiary-bg);
  border-radius: .35rem;
  overflow: hidden;
  height: 1.1rem;
}

.stat-bar-fill {
  background: var(--bs-primary);
  height: 100%;
}

.stat-bar-count {
  width: 3rem;
  flex: 0 0 3rem;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-size: .85rem;
}

/* --- login: escena de la lampara con soguita + card de acceso ---
   Porte fiel (a JS/CSS vanilla, sin GSAP) de la demo "Login Form Lamp"
   de codewithbhurtel.com/projects/73 que pidio el usuario: mismas curvas
   de easing, mismo glow radial de fondo, mismo snap elastico del cordon,
   mismo look de vidrio esmerilado en el formulario -- ver style.css del
   zip original para las referencias de valores.
*/

.login-scene {
  --ease-smooth: cubic-bezier(.4, 0, .2, 1);
  --ease-back: cubic-bezier(.34, 1.56, .64, 1);
  position: relative;
  padding: 2rem 1rem;
  isolation: isolate;
  /* lampara y form lado a lado en desktop -- en pantallas angostas, como
     no entran los dos en una fila, flex-wrap los apila solo (sin
     necesitar un breakpoint especifico). */
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 3rem;
}

.login-scene-glow {
  /* fixed + inset:0 = todo el viewport, no solo el recuadro de la escena
     -- si no, se nota un borde recto donde termina el degradado (bug
     reportado: "se circunscribe solo a un div"). isolation:isolate en
     .login-scene (mas arriba) hace que este siga apilandose por detras
     del resto del contenido de la escena aunque este posicionado fixed. */
  position: fixed;
  inset: 0;
  z-index: -1;
  /* centrado en 50% 50% -- antes estaba fijo en 32% desde arriba, un
     resto de cuando la lampara no estaba centrada verticalmente en el
     viewport (ahora el row usa min-vh-100 + align-items-center, asi que
     el centro real de la escena es el centro real de la pantalla). */
  background: radial-gradient(circle at 50% 50%, rgba(255, 214, 110, .35), transparent 60%);
  opacity: 0;
  transition: opacity .6s var(--ease-smooth);
  pointer-events: none;
}

/* el div de glow es un hermano de #antibot-lamp, no un descendiente --
   por eso necesita su propio selector de atributo en vez de heredar el
   [data-on] de mas arriba (bug de la primera version: --on quedaba fijo
   en 0 porque nada lo actualizaba, el glow nunca se veia). */
.login-scene[data-on="true"] .login-scene-glow {
  opacity: 1;
}

.google-login-btn {
  font-weight: 500;
}

.google-login-btn[aria-disabled="true"] {
  opacity: .55;
}

.antibot-lamp-wrapper {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  user-select: none;
}

.antibot-lamp-svg {
  width: 290px;
  height: 319px;
  overflow: visible;
}

.antibot-lamp-shade {
  fill: #e8e2d9;
  transition: fill .5s var(--ease-smooth), filter .5s var(--ease-smooth);
}

.login-scene[data-on="true"] .antibot-lamp-shade {
  fill: #fffaf0;
  filter: drop-shadow(0 0 26px rgba(255, 214, 110, .6));
}

.antibot-lamp-base {
  fill: #b9b2a6;
  transition: fill .5s var(--ease-smooth);
}

.login-scene[data-on="true"] .antibot-lamp-base {
  fill: #cdc4b4;
}

.antibot-lamp-glow {
  fill: #ffdb8a;
  opacity: 0;
  filter: blur(14px);
  transition: opacity .5s var(--ease-smooth);
}

.login-scene[data-on="true"] .antibot-lamp-glow {
  opacity: .7;
}

.antibot-lamp-cord-line {
  stroke: #8a8375;
  stroke-width: 2;
  transition: y2 .45s var(--ease-back), stroke .3s var(--ease-smooth);
}

.antibot-lamp-cord-bead {
  fill: #d4a373;
  transform-box: fill-box;
  transform-origin: center;
  transition: cy .45s var(--ease-back), fill .3s var(--ease-smooth), transform .25s var(--ease-smooth);
}

/* feedback visual del long-press (paso 2->3): la perlita crece durante
   los 650ms que hay que mantener apretado -- si no hay NADA que se mueva
   en pantalla mientras se espera, el gesto se sentia "roto"/sin
   respuesta (bug reportado). .65s debe coincidir con LONG_PRESS_MS del
   JS. Si se suelta antes de completarse, la transicion de arriba (.25s)
   la vuelve a su tamaño normal. */
.login-scene.holding .antibot-lamp-cord-bead {
  transform: scale(1.8);
  transition: transform .65s linear;
}

.antibot-lamp-cord-hit {
  cursor: grab;
  transition: cy .45s var(--ease-back);
}

.login-scene[data-on="true"] .antibot-lamp-cord-bead {
  fill: #f0c179;
}

/* mientras se arrastra, sin transicion -- si no, el cordon "persigue" al
   mouse con retraso en vez de seguirlo 1 a 1; el snap-back/snap-to-open
   elastico (--ease-back, con overshoot) solo se ve al SOLTAR. */
.login-scene.dragging .antibot-lamp-cord-line,
.login-scene.dragging .antibot-lamp-cord-bead,
.login-scene.dragging .antibot-lamp-cord-hit {
  transition: none;
}

.antibot-lamp-cord-hit:active {
  cursor: grabbing;
}

@keyframes antibot-shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-6px); }
  75% { transform: translateX(6px); }
}

.antibot-shake {
  animation: antibot-shake .3s ease;
}

/* Card de acceso: vidrio esmerilado, aparece con fade + "pop" elastico
   igual que el .login-form del original -- oculta hasta prender la
   lampara. */
.login-card {
  /* max-width/padding en 0 mientras esta inactiva -- si no, aunque sea
     invisible (opacity:0) sigue ocupando sus 380px en el flex de
     .login-scene y descentra la lampara del medio real de la pantalla
     (bug encontrado al probar el centrado vertical/horizontal). */
  flex: 0 1 380px;
  width: 100%;
  max-width: 0;
  padding: 0;
  overflow: hidden;
  border-radius: 26px;
  background: rgba(127, 127, 127, .07);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid var(--bs-border-color-translucent, rgba(127, 127, 127, .18));
  /* sombra grande y marcada, mas fuerte que el .login-form del original
     (box-shadow: 0 20px 40px rgba(0,0,0,.3)) para que se note el
     recuadro tambien sobre fondos claros. */
  box-shadow: 0 10px 20px rgba(0, 0, 0, .16),
              0 30px 60px rgba(0, 0, 0, .4),
              inset 0 1px 0 rgba(255, 255, 255, .08);

  opacity: 0;
  transform: translateY(24px) scale(.98);
  pointer-events: none;
  transition: opacity .6s var(--ease-back), transform .6s var(--ease-back),
              max-width .6s var(--ease-back), padding .6s var(--ease-back),
              box-shadow .6s var(--ease-smooth), border-color .6s var(--ease-smooth);
}

.login-card.active {
  max-width: 380px;
  padding: 2rem;
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
  /* la sombra "recibe" el glow calido de la lampara encendida en vez de
     una sombra neutra plana -- ata visualmente la card a la escena. */
  box-shadow: 0 10px 20px rgba(0, 0, 0, .18),
              0 32px 64px rgba(191, 149, 63, .32),
              inset 0 1px 0 rgba(255, 255, 255, .12);
  border-color: rgba(212, 163, 115, .35);
}

.login-submit-btn {
  border: none;
  color: #2b2109;
  font-weight: 600;
  background: linear-gradient(135deg, #bf953f, #fcf6ba, #b38728, #fcf6ba, #aa771c);
  background-size: 200% 200%;
  background-position: 0% 50%;
  transition: background-position .4s var(--ease-smooth), transform .2s var(--ease-smooth), opacity .3s;
}

.login-submit-btn:hover:not(:disabled) {
  background-position: 100% 50%;
  transform: scale(1.01);
}

.login-submit-btn:disabled {
  opacity: .45;
  background: var(--bs-tertiary-bg);
  color: var(--bs-secondary-color);
}
