/* WZAPI dashboard — page styles + deep Fomantic override layer.
 * Design tokens come from /css/wz.css (dark default, light via :root[data-theme="light"]). */

body {
  background: var(--bg);
  color: var(--text);
  font: 15px/1.55 "Space Grotesk", system-ui, sans-serif;
}

/* ---------- functional helpers the JS depends on ---------- */
.hidden { display: none !important; }
.p1 { padding-left: 1em; padding-right: 1em; }
.adminlogin { display: none; }
#proxyUrlField { display: none; }
#proxyUrlField.show { display: block; }
#deleteS3Config { display: none; }
.required { color: var(--red); }

/* ---------- topbar extras ---------- */
.topbar { flex-wrap: nowrap; gap: 18px; }
.topbar-session { display: inline-flex; align-items: center; gap: 12px; }
.role-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: .68rem; font-weight: 700; letter-spacing: .14em;
  border-radius: 999px; padding: 3px 10px;
  background: var(--green-soft); border: 1px solid var(--green-line); color: var(--green);
}
.role-chip.admin { background: rgba(255,92,92,.12); border-color: rgba(255,92,92,.4); color: var(--red); }
/* topbar Logout is a .btn-ghost .btn-sm; only tone down its resting color */
.logout-link { color: var(--muted); }
.logout-link:hover { color: var(--text); border-color: var(--border-hi); }
.lang-btn { width: auto; padding: 0 10px; border-radius: 999px; font-size: .72rem; font-weight: 700; letter-spacing: .08em; }
.ico-moon { display: none; }
:root[data-theme="light"] .ico-sun { display: none; }
:root[data-theme="light"] .ico-moon { display: block; }
/* Seis enlaces dejan de caber junto al chip de sesión alrededor de 900px.
   Esconder la nav ahí (lo que hacía este bloque) dejaba las tabletas sin
   navegación; darle una fila propia con scroll lateral mantiene los enlaces
   alcanzables y, sobre todo, deja los botones de tema/idioma dentro del
   viewport en vez de empujarlos fuera del borde derecho. */
/* Red de seguridad para los anchos justo por encima del corte: sin min-width:0
   la nav no encoge nunca y basta un idioma más largo para sacar los botones de
   la derecha del viewport. */
.topnav { min-width: 0; overflow-x: auto; scrollbar-width: none; }
.topnav::-webkit-scrollbar { display: none; }
@media (max-width: 900px) {
  .topbar { flex-wrap: wrap; gap: 10px 16px; }
  .topnav { order: 10; width: 100%; margin-left: 0; overflow-x: auto; white-space: nowrap; scrollbar-width: none; }
  .topnav::-webkit-scrollbar { display: none; }
}
/* El dashboard lleva chip de rol + logout que las demás páginas no tienen, y a
   360px el botón de idioma no cabía tras ellos: caía a una tercera fila y la
   barra subía a 177px (28% de la pantalla) contra los 123-127px del resto. Se
   comprime la sesión —gaps y padding— en vez de esconder nada, y todo vuelve a
   una fila (Issue #500 D17). */
@media (max-width: 560px) {
  .badge-live { display: none; }
  .topbar { gap: 8px; padding: 12px 16px; }
  .topbar-session { gap: 6px; }
  .role-chip { padding: 3px 7px; letter-spacing: .06em; }
  .logout-link { padding: 0 8px; }
}

/* ---------- sections ---------- */
.sec-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 18px; }
.sec-row .sub { margin-bottom: 0; }
.hint { color: var(--dim); font-size: .8rem; margin: 8px 0 0; }
.chips-row { display: flex; gap: 8px; margin-bottom: 18px; flex-wrap: wrap; }
.chips-row .chip { cursor: pointer; font-family: inherit; }
.card.no-hover:hover, .card.panel-card:hover { border-color: var(--border); box-shadow: none; transform: none; }
.action-card { cursor: pointer; }

/* ---------- login (same shell as /login/: beam + big W + centered card) ---------- */
.login-shell {
  min-height: calc(100vh - 63px);
  display: grid;
  place-items: center;
  position: relative;
  overflow: hidden;
  padding: 44px 0;
}
.beam {
  position: absolute;
  inset: 0;
  background: radial-gradient(600px 300px at 50% 0%, var(--green-soft), transparent 70%);
  pointer-events: none;
}
.login-col { width: min(420px, 92vw); position: relative; }
.big-logo {
  width: 56px; height: 56px; border-radius: 16px;
  background: var(--green); display: grid; place-items: center;
  color: #04140b; font-weight: 800; font-size: 26px;
  margin: 0 auto 18px; box-shadow: var(--glow);
}
.login-title { text-align: center; font-size: 1.9rem; }
.login-lede { text-align: center; margin: 0 auto 26px; font-size: .92rem; }
.login-card { padding: 26px; }
.login-card label.f { text-transform: uppercase; }
.login-card .input { margin-bottom: 6px; }
.enter-hint { display: block; color: var(--dim); font-size: .72rem; margin: 0 0 14px; }
.login-actions { display: flex; flex-direction: column; gap: 10px; }
.login-btn { width: 100%; justify-content: center; }
.login-meta {
  display: flex; justify-content: space-between;
  margin-top: 16px; font-size: .78rem; color: var(--dim);
}
.login-hint { text-align: center; color: var(--dim); font-size: .78rem; margin-top: 18px; }
.login-help { margin-top: 18px; }
.login-help b { display: block; margin-bottom: 4px; font-size: .84rem; }
.login-help p { margin: 0; color: var(--muted); font-size: .84rem; }
/* app.js toggles the old Fomantic "teal" class for admin mode — restyle it on-brand */
#loginAsAdminBtn.teal {
  background: var(--green-soft);
  border-color: var(--green-line);
  color: var(--green);
}

/* ---------- buscador + filtro de sesiones (#791) ---------- */
.sesiones-filtros {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 14px;
}
.sesiones-filtros .buscador { position: relative; flex: 1 1 260px; min-width: 200px; }
.sesiones-filtros input[type="search"],
.sesiones-filtros select {
  width: 100%;
  padding: 9px 12px;
  border-radius: 10px;
  border: 1px solid var(--green-line);
  background: var(--card2, var(--bg));
  color: inherit;
  font-family: inherit;
  font-size: .88rem;
}
.sesiones-filtros select { width: auto; flex: 0 0 auto; cursor: pointer; }
.sesiones-filtros input[type="search"]:focus,
.sesiones-filtros select:focus { outline: none; border-color: var(--green); }
/* Spinner del buscador: gira mientras vuela la petición del filtro. */
.buscador-spin {
  position: absolute; top: 50%; right: 12px; width: 14px; height: 14px;
  margin-top: -7px; border-radius: 50%;
  border: 2px solid var(--green-line); border-top-color: var(--green);
  animation: buscador-gira .7s linear infinite;
}
@keyframes buscador-gira { to { transform: rotate(360deg); } }
@media (max-width: 640px) {
  .sesiones-filtros { flex-direction: column; align-items: stretch; }
  .sesiones-filtros select { width: 100%; }
}

/* ---------- admin table ---------- */
.tbl-card { padding: 0; position: relative; overflow: hidden; }
.tbl-wrap { overflow-x: auto; }
.tbl-empty { text-align: center; color: var(--muted); }
.dot-ok, .dot-bad { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 7px; }
.dot-ok { background: var(--green); box-shadow: 0 0 8px var(--green); }
.dot-bad { background: var(--red); }
/* "Se desconoce" no es ni verde ni rojo. De una sesión que sostiene otro pod,
   este panel no puede afirmar el estado, y pintarla de rojo era decir
   "desconectada" de una sesión que está funcionando. */
.dot-unk { display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  margin-right: 7px; background: var(--muted); }
/* Estado vivo en frío: la foto de la flota aún no llegó, así que de una sesión
   que sostiene otro pod no se sabe el estado TODAVÍA. No es "Se desconoce"
   —eso es un veredicto que exige haber preguntado—, es que está cargando. Un
   skeleton lo dice sin pintar un "Unknown" plano sobre una sesión viva (#803). */
.skeleton-cell {
  display: inline-block; width: 34px; height: 10px; border-radius: 5px;
  vertical-align: middle;
  background: linear-gradient(90deg, var(--card2) 25%, var(--border-hi) 37%, var(--card2) 63%);
  background-size: 400% 100%;
  animation: wz-skeleton 1.2s ease-in-out infinite;
}
@keyframes wz-skeleton { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }
@media (prefers-reduced-motion: reduce) { .skeleton-cell { animation: none; } }
/* Filas fantasma del listado de grupos mientras carga (#804): el hueco de ~4s
   se lee como "cargando" y no se funde con el empty-state "no hay grupos".
   Reusan el shimmer de .skeleton-cell, sólo cambian la silueta a la de una fila. */
.group-skeleton-item .skeleton-cell { height: 12px; }
.group-skeleton-item .skeleton-icon { width: 24px; height: 24px; border-radius: 6px; }
.group-skeleton-item .skeleton-line-title { width: 45%; max-width: 220px; }
.group-skeleton-item .skeleton-line-meta { width: 25%; max-width: 140px; }
.tbl td .btn { margin-right: 6px; }

/* En un teléfono, el identificador de 32 caracteres es lo MENOS útil de la fila
   y era lo que se llevaba toda la anchura: el nombre, el pod y los botones
   quedaban fuera de la pantalla y había que arrastrar la tabla para llegar a
   ellos. Se recorta con puntos suspensivos y el valor entero sigue estando en
   el `title`, que es donde se copia. */
@media (max-width: 760px) {
  .tbl td.id-cell {
    max-width: 9ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
}

/* Pie de la lista: siempre visible, aunque quepa entera. Una lista sin pie es
   indistinguible de una lista cortada, que es como el panel enseñaba un censo
   truncado con cara de completo. */
.pager {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 18px; border-top: 1px solid var(--green-line);
}
.pager-range { color: var(--muted); font-size: .8rem; margin-right: auto; }
.pager .btn[disabled], .pager .btn:disabled { opacity: .35; cursor: default; pointer-events: none; }
@media (max-width: 640px) {
  .pager { justify-content: space-between; }
  .pager-range { width: 100%; margin-right: 0; }
}

/* ---------- session card ---------- */
.session-zone { padding-top: 26px; }
.session-zone .eyebrow { margin-bottom: 10px; }
.back-row { text-align: right; margin: 14px 0; }
.session-card { margin-bottom: 14px; }
.session-head { display: flex; align-items: center; gap: 14px; margin-bottom: 14px; flex-wrap: wrap; }
.session-head .ic { margin: 0; flex: none; }
.session-id h3 { margin: 0; font-size: 1.15rem; }
.session-id .route { font-size: .78rem; word-break: break-all; }
.session-chips { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }
.chip.warn { color: var(--amber); border-color: rgba(255,176,32,.4); background: rgba(255,176,32,.08); }
.chip.err { color: var(--red); border-color: rgba(255,92,92,.4); background: rgba(255,92,92,.08); }
.session-body { display: grid; grid-template-columns: 1fr; gap: 20px; }
.session-body.with-side { grid-template-columns: 1.6fr 1fr; }
.session-kvs .kv b { text-align: right; word-break: break-all; max-width: 60%; }
.qr-panel {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12px; text-align: center;
  border: 1px dashed var(--green-line); border-radius: 12px; padding: 18px;
  background: radial-gradient(220px 140px at 50% 0%, var(--green-soft), transparent 75%);
}
.qr-panel img { width: 200px; max-width: 100%; border-radius: 10px; background: #fff; padding: 8px; border: 4px solid var(--green); }
.qr-panel p { margin: 0; color: var(--muted); font-size: .82rem; }
.qr-empty { color: var(--dim); font-size: .85rem; display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 14px 0; }
/* placeholder QR glyph so the empty state looks designed, not broken */
.qr-empty::before {
  content: "";
  width: 64px; height: 64px; opacity: .75;
  background: currentColor;
  -webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.6"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><path d="M14 14h3v3h-3zM21 14v3m-4 4h4"/></svg>') center / contain no-repeat;
  mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.6"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><path d="M14 14h3v3h-3zM21 14v3m-4 4h4"/></svg>') center / contain no-repeat;
}
.session-actions { display: flex; gap: 10px; margin-top: 18px; flex-wrap: wrap; }

/* Aviso de «esta sesión la sostiene otro pod» (#778). Va entre el cuerpo de la
   tarjeta y los botones a propósito: es lo que hay que leer ANTES de pulsar
   nada, porque conectar desde aquí abre un segundo socket sobre la misma
   cuenta. Sin él, la tarjeta de una sesión ajena era indistinguible de la de
   una sesión parada. */
.aviso-otro-pod {
  margin-top: 18px;
  padding: 10px 12px;
  border-radius: 8px;
  font-size: .86rem;
  color: var(--amber);
  border: 1px solid rgba(255,176,32,.4);
  background: rgba(255,176,32,.08);
}
@media (max-width: 760px) { .session-body.with-side { grid-template-columns: 1fr; } }

/* ---------- groups manager ---------- */
.gm-toolbar { display: grid; grid-template-columns: 1.6fr 1fr auto auto; gap: 10px; align-items: center; margin-bottom: 18px; }
@media (max-width: 860px) { .gm-toolbar { grid-template-columns: 1fr 1fr; } }
@media (max-width: 520px) { .gm-toolbar { grid-template-columns: 1fr; } }
.gm-body { position: relative; min-height: 160px; }
.empty-state { text-align: center; padding: 40px 20px; }
.empty-state .ic { margin: 0 auto 12px; }
.empty-state h3 { margin: 0 0 14px; }

.group-list-item { padding: 16px 0; }
.group-list-item .header { font-size: 1.02rem; font-weight: 600; margin-bottom: 4px; color: var(--text); }
.group-list-item .meta { color: var(--muted); font-size: .82rem; margin-top: 6px; line-height: 1.7; }
.group-list-item .meta span { margin-right: 14px; display: inline-flex; align-items: center; gap: .3rem; }
.group-list-item .description { margin: 4px 0; color: var(--muted); font-size: .88rem; line-height: 1.5; }
.read-more-link { color: var(--green); cursor: pointer; font-weight: 500; }
.read-more-link:hover { text-decoration: underline; }

/* participant rows */
.participant-item .content { display: flex; justify-content: space-between; align-items: flex-start; width: 100%; gap: 10px; }
.participant-info { flex: 1; }
.participant-item .participant-info .header { color: var(--text); }
.participant-item .participant-info .description { color: var(--muted); font-family: "JetBrains Mono", monospace; font-size: .8rem; }
.participant-actions { display: flex; flex-direction: column; align-items: flex-end; gap: .5rem; }
.participant-labels { display: flex; gap: .3rem; flex-wrap: wrap; justify-content: flex-end; }
@media (max-width: 600px) {
  .participant-item .content { flex-direction: column; }
  .participant-actions { align-items: flex-start; }
}

/* photo box (group modals) */
.photo-box { display: flex; align-items: center; gap: 18px; border: 1px solid var(--border); border-radius: 12px; padding: 14px; flex-wrap: wrap; }
.photo-preview { width: 80px; height: 80px; border-radius: 50%; background: var(--card2); display: flex; align-items: center; justify-content: center; overflow: hidden; flex: none; }
.photo-preview img { width: 100%; height: 100%; object-fit: cover; }
.photo-empty { color: var(--dim); font-size: .72rem; text-align: center; padding: 4px; }
.photo-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.load-contacts-row { margin-bottom: 10px; }
.invite-box { border: 1px solid var(--border); border-radius: 12px; padding: 16px; margin-bottom: 16px; }
.invite-box small { color: var(--dim); display: block; margin-top: 8px; }
.danger-text { color: var(--red); font-weight: 700; }
.wh-content { min-height: 380px; }

/* Failure banner inside the config modals: what the gateway answered stays on
   screen next to the form that failed, instead of only flashing past in a toast. */
.wz-modal-error {
  display: none;
  margin: 0 0 16px !important;
  font-size: .86rem;
  overflow-wrap: anywhere;
}

/* Aviso de "todavía estoy leyendo la configuración": mientras esté visible, lo
   que se ve en el formulario no es lo que hay guardado, y guardar está vetado.
   Sin él, un GET colgado se ve exactamente igual que uno que cargó bien. */
.wz-modal-busy {
  display: none;
  margin: 0 0 16px !important;
  font-size: .86rem;
}

/* ----- delete-instance modal: two operations, one button -----
   The plain delete and /full are not the same thing (only /full unlinks the
   device from WhatsApp), so both are spelled out and neither is preselected. */
.del-target {
  margin: 0 0 14px !important;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card2);
  color: var(--text) !important;
  font-size: .82rem;
  overflow-wrap: anywhere;
}
.del-modes { display: flex; flex-direction: column; gap: 10px; }
.del-mode {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--card);
  cursor: pointer;
}
.del-mode:hover { border-color: var(--border-hi); }
.del-mode input[type="radio"] { margin-top: 3px; accent-color: var(--green-fill); flex: 0 0 auto; }
.del-mode:has(input:checked) { border-color: var(--green-line); background: var(--green-soft); }
.del-mode-txt { display: flex; flex-direction: column; gap: 4px; }
.del-mode-txt b { color: var(--text); font-size: .86rem; }
.del-mode-txt span { color: var(--muted); font-size: .8rem; line-height: 1.45; }
.del-warn {
  margin-top: 14px;
  padding: 10px 12px;
  border: 1px solid var(--red-line);
  border-radius: 12px;
  background: var(--red-soft);
}
.del-warn b { color: var(--red); font-size: .84rem; }
.del-warn ul { margin: 8px 0 0; padding-left: 18px; }
.del-warn li { color: var(--text); font-size: .8rem; line-height: 1.5; margin-bottom: 5px; }
.del-warn li:last-child { margin-bottom: 0; }
/* The confirm button turns red only once "complete delete" is the armed choice. */
.ui.modal > .actions .ui.positive.button.btn-danger-confirm {
  background: var(--red) !important;
  border-color: var(--red) !important;
  color: #fff !important;
}

/* footer */
.foot .dot-g { vertical-align: middle; }

/* =====================================================================
   Fomantic override layer — modals, forms, dropdowns, toasts, dimmers
   Everything uses wz.css variables so both themes work.
   ===================================================================== */

/* ----- modal shell ----- */
.ui.modal,
.ui.modal > .content {
  background: var(--card) !important;
  color: var(--text) !important;
}
.ui.modal {
  border: 1px solid var(--border) !important;
  border-radius: var(--radius) !important;
  box-shadow: 0 20px 60px rgba(0,0,0,.5) !important;
  overflow: hidden;
}
.ui.modal > .header {
  background: var(--card) !important;
  color: var(--text) !important;
  font-family: "Space Grotesk", system-ui, sans-serif !important;
  font-size: 1.1rem !important;
  font-weight: 700 !important;
  border-bottom: 1px solid var(--border) !important;
  padding: 18px 22px !important;
}
.ui.modal > .content { padding: 22px !important; }
.ui.modal > .actions {
  background: var(--card2) !important;
  border-top: 1px solid var(--border) !important;
  padding: 14px 22px !important;
}
.ui.modal > .close.icon { color: var(--muted) !important; top: .8rem !important; right: .8rem !important; }
.ui.modal > .close.icon:hover { color: var(--text) !important; }
.ui.dimmer { background-color: rgba(0, 0, 0, .72) !important; }
.ui.modal .ui.header, .ui.modal h4.ui.header, .ui.modal h5.ui.header { color: var(--text) !important; }
.ui.modal .ui.dividing.header { border-bottom: 1px solid var(--border) !important; color: var(--green) !important; font-size: .8rem !important; text-transform: uppercase; letter-spacing: .12em; padding-bottom: 8px !important; }
.ui.modal .ui.red.header { color: var(--red) !important; }
.ui.modal .ui.divider { border-top: 1px solid var(--border) !important; border-bottom: none !important; }
.ui.modal ol { color: var(--muted); }
.ui.modal p { color: var(--muted); }
.ui.modal .danger-text { color: var(--red); }

/* lists inside modals */
.ui.list .item .header, .ui.relaxed.list .item .header { color: var(--text) !important; }
.ui.list .item, .ui.relaxed.list .item { color: var(--muted) !important; }
.ui.divided.list > .item { border-top: 1px solid var(--border) !important; }

/* ----- forms ----- */
.ui.form .field > label { color: var(--muted) !important; font-size: .78rem !important; letter-spacing: .04em; font-weight: 500 !important; }
.ui.form input:not([type]), .ui.form input[type="text"], .ui.form input[type="password"],
.ui.form input[type="number"], .ui.form input[type="url"], .ui.form input[type="email"],
.ui.form textarea {
  background: var(--bg2) !important;
  border: 1px solid var(--border) !important;
  border-radius: 10px !important;
  color: var(--text) !important;
  font-family: inherit !important;
  padding: 11px 14px !important;
}
/* El outline va aquí y no sólo en wz.css porque Fomantic pinta su propio :focus con
   especificidad alta; el borde verde y el halo son decoración (1.49:1 claro / 2.10:1 oscuro
   contra el campo) y el indicador que cumple SC 1.4.11 es este anillo en --focus. */
.ui.form input:focus, .ui.form textarea:focus {
  border-color: var(--green-line) !important;
  box-shadow: 0 0 0 3px var(--green-soft) !important;
  background: var(--bg2) !important;
  color: var(--text) !important;
  outline: 2px solid var(--focus) !important;
  outline-offset: 2px !important;
}
.ui.form input::placeholder, .ui.form textarea::placeholder { color: var(--dim) !important; }
.ui.form .field small, .ui.form small { color: var(--dim); font-size: .76rem; display: block; margin-top: 4px; }
.ui.form .field.error input, .ui.form .field.error textarea { border-color: rgba(255,92,92,.6) !important; }
.ui.input > input { background: var(--bg2) !important; border: 1px solid var(--border) !important; color: var(--text) !important; border-radius: 10px !important; }
.ui.action.input > .button { border-radius: 0 10px 10px 0 !important; }

/* ----- fomantic buttons -> wz pills ----- */
.ui.button {
  border-radius: 999px !important;
  font-family: inherit !important;
  font-weight: 600 !important;
  padding: 9px 18px !important;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
  transition: filter .15s, border-color .15s, background .15s;
}
.ui.button:hover { border-color: var(--border-hi); color: var(--text); background: var(--card2); }
/* Los controles de los modales son <button> reales (antes eran <div>, que no
   recibe foco: con teclado se podía abrir y rellenar un modal pero no enviarlo
   ni cancelarlo). Como ahora sí reciben foco, hace falta que se VEA: Fomantic
   pinta su propio :focus gris (.ui.button:focus{background-color:#cacbcd}) que
   además rompe el color del tema, así que aquí se devuelve el aspecto del
   sistema de diseño y el indicador real es el anillo en --focus, el mismo token
   con contrato >=3:1 (SC 1.4.11) que usan los campos.
   :focus-visible y no :focus, para no dibujar el anillo en cada clic de ratón. */
.ui.button:focus { background: transparent; color: var(--text); }
.ui.button:focus-visible,
.ui.modal > .close.icon:focus-visible {
  outline: 2px solid var(--focus) !important;
  outline-offset: 2px;
  border-radius: 999px;
}
.ui.modal > .close.icon:focus-visible { border-radius: 6px; }
.ui.positive.button, .ui.primary.button, .ui.green.button, .ui.blue.button {
  background: var(--green) !important;
  color: #04140b !important;
  border-color: transparent !important;
}
.ui.positive.button:hover, .ui.primary.button:hover, .ui.green.button:hover, .ui.blue.button:hover {
  filter: brightness(1.08);
  box-shadow: var(--glow);
}
.ui.secondary.button, .ui.black.button, .ui.cancel.button, .ui.deny.button {
  background: transparent !important;
  color: var(--text) !important;
  border: 1px solid var(--border) !important;
}
.ui.secondary.button:hover, .ui.black.button:hover, .ui.cancel.button:hover, .ui.deny.button:hover { border-color: var(--border-hi) !important; }
.ui.negative.button, .ui.red.button {
  background: transparent !important;
  color: var(--red) !important;
  border: 1px solid rgba(255,92,92,.4) !important;
}
.ui.negative.button:hover, .ui.red.button:hover { background: rgba(255,92,92,.1) !important; }
.ui.orange.button {
  background: transparent !important;
  color: var(--amber) !important;
  border: 1px solid rgba(255,176,32,.45) !important;
}
.ui.orange.button:hover { background: rgba(255,176,32,.1) !important; }
.ui.purple.button {
  background: transparent !important;
  color: var(--blue) !important;
  border: 1px solid rgba(77,163,255,.45) !important;
}
.ui.purple.button:hover { background: rgba(77,163,255,.1) !important; }
.ui.grey.button { background: transparent !important; color: var(--muted) !important; border: 1px solid var(--border) !important; }
.ui.mini.button { padding: 5px 12px !important; font-size: .72rem !important; }
.ui.small.buttons .button { padding: 7px 14px !important; font-size: .8rem !important; }
.ui.buttons { gap: 8px; display: inline-flex; flex-wrap: wrap; }
.ui.buttons .button { border-radius: 999px !important; }
.ui.buttons .or { display: none; }
.ui.fluid.buttons { display: flex; }
.ui.fluid.buttons .button { flex: 1; }
.ui.icon.button { padding: 9px 12px !important; }
.ui.button.loading { pointer-events: none; opacity: .7; }
/* La capa de arriba pinta el botón positivo con !important, así que el
   `opacity` que Fomantic aplica a .disabled quedaba anulado: el botón de
   guardar se veía idéntico estando inerte. Un botón que no responde tiene que
   verse. */
.ui.button.disabled, .ui.buttons .button.disabled {
  opacity: .45 !important;
  pointer-events: none !important;
  box-shadow: none !important;
}

/* ----- messages ----- */
.ui.message {
  background: var(--card2) !important;
  border: 1px solid var(--border) !important;
  border-radius: 12px !important;
  color: var(--muted) !important;
  box-shadow: none !important;
}
.ui.message .header { color: var(--text) !important; }
.ui.info.message { border-color: var(--green-line) !important; background: var(--green-soft) !important; }
.ui.info.message .header { color: var(--green) !important; }
.ui.warning.message { border-color: rgba(255,176,32,.4) !important; background: rgba(255,176,32,.08) !important; }
.ui.warning.message .header { color: var(--amber) !important; }
.ui.error.message, .ui.negative.message { border-color: rgba(255,92,92,.4) !important; background: rgba(255,92,92,.08) !important; color: var(--red) !important; }
.ui.success.message { border-color: var(--green-line) !important; background: var(--green-soft) !important; color: var(--green) !important; }
.login-help.ui.info.message { margin-top: 22px; }

/* ----- dropdowns ----- */
.ui.selection.dropdown, .ui.dropdown.selection, .ui.fluid.dropdown {
  background: var(--bg2) !important;
  border: 1px solid var(--border) !important;
  border-radius: 10px !important;
  color: var(--text) !important;
  min-height: auto;
}
.ui.selection.dropdown:focus, .ui.selection.active.dropdown {
  border-color: var(--green-line) !important;
  box-shadow: 0 0 0 3px var(--green-soft) !important;
}
/* Sólo el foco de teclado/click lleva anillo; .active.dropdown (menú abierto) no es un
   estado de foco y no debe pintarlo. */
.ui.selection.dropdown:focus {
  outline: 2px solid var(--focus) !important;
  outline-offset: 2px !important;
}
.ui.selection.dropdown .menu, .ui.dropdown .menu {
  background: var(--card) !important;
  border: 1px solid var(--border) !important;
  border-radius: 0 0 10px 10px !important;
  box-shadow: 0 12px 30px rgba(0,0,0,.45) !important;
}
.ui.dropdown .menu > .item {
  color: var(--text) !important;
  border-top: 1px solid var(--border) !important;
  font-size: .88rem !important;
}
.ui.dropdown .menu > .item:hover, .ui.dropdown .menu > .item.selected { background: var(--card2) !important; color: var(--green) !important; }
.ui.dropdown .menu > .item.disabled { color: var(--dim) !important; }
.ui.dropdown > .text { color: var(--text) !important; }
.ui.dropdown > .default.text, .ui.default.dropdown > .text { color: var(--dim) !important; }
.ui.dropdown > .dropdown.icon { color: var(--muted) !important; }
.ui.multiple.dropdown > .label {
  background: var(--green-soft) !important;
  border: 1px solid var(--green-line) !important;
  color: var(--green) !important;
  border-radius: 999px !important;
  box-shadow: none !important;
  font-size: .74rem !important;
}
.ui.multiple.dropdown > .label .delete.icon { color: var(--green) !important; opacity: .8; }
.ui.search.dropdown > input.search { color: var(--text) !important; font-family: inherit !important; }
.ui.active.selection.dropdown { border-bottom-left-radius: 0 !important; border-bottom-right-radius: 0 !important; }

/* ----- checkboxes / toggles ----- */
.ui.checkbox label, .ui.toggle.checkbox label { color: var(--text) !important; }
.ui.checkbox label:hover, .ui.toggle.checkbox label:hover { color: var(--text) !important; }
.ui.checkbox label:before { background: var(--bg2) !important; border: 1px solid var(--border) !important; }
.ui.checkbox label:after { color: var(--green) !important; }
.ui.checkbox input:checked ~ label:before { background: var(--green-soft) !important; border-color: var(--green-line) !important; }
.ui.toggle.checkbox label:before { background: var(--border) !important; border: none !important; }
.ui.toggle.checkbox label:after { background: var(--text) !important; box-shadow: none !important; }
.ui.toggle.checkbox input:checked ~ label:before { background: var(--green) !important; }
.ui.toggle.checkbox input:checked ~ label:after { background: #04140b !important; }
.ui.toggle.checkbox input:focus:checked ~ label:before { background: var(--green) !important; }

/* ----- dimmers / loaders ----- */
/* Fomantic's .ui.form.loading paints a WHITE overlay + old-teal loader — retheme it */
.ui.form.loading::before { background: color-mix(in srgb, var(--bg) 72%, transparent) !important; border-radius: 12px; }
.ui.form.loading::after {
  border-color: var(--green) var(--border) var(--border) !important;
}
.ui.inverted.dimmer { background: color-mix(in srgb, var(--bg) 78%, transparent) !important; }
.ui.inverted.dimmer .ui.loader { color: var(--muted) !important; }
.ui.inverted.dimmer .ui.loader:before { border-color: var(--border) !important; }
.ui.inverted.dimmer .ui.loader:after { border-color: var(--green) transparent transparent !important; }
.tbl-card .ui.dimmer { border-radius: var(--radius); }

/* ----- toasts -----
   Aquí vivían veinte líneas de !important para que el toast de Fomantic se
   pareciera al resto de la casa. Se fueron con la #800: los avisos los pinta
   wz-toast.js, que es nuestro y no hay que repintar. El estilo está en
   static/css/wz.css junto al del diálogo de confirmación, porque lo comparten
   el dashboard, el panel de admin y /login. */

/* ----- labels (role/type badges rendered by groups.js) ----- */
.ui.label {
  border-radius: 999px !important;
  font-weight: 600 !important;
  font-size: .68rem !important;
  background: var(--card2) !important;
  color: var(--muted) !important;
  border: 1px solid var(--border) !important;
}
.ui.red.label { background: rgba(255,92,92,.12) !important; color: var(--red) !important; border-color: rgba(255,92,92,.4) !important; }
.ui.orange.label { background: rgba(255,176,32,.12) !important; color: var(--amber) !important; border-color: rgba(255,176,32,.4) !important; }
.ui.blue.label { background: rgba(77,163,255,.12) !important; color: var(--blue) !important; border-color: rgba(77,163,255,.4) !important; }
.ui.green.label { background: var(--green-soft) !important; color: var(--green) !important; border-color: var(--green-line) !important; }
.ui.purple.label { background: rgba(142,68,173,.18) !important; color: #b07cc6 !important; border-color: rgba(142,68,173,.45) !important; }
.ui.grey.label { background: var(--card2) !important; color: var(--muted) !important; border-color: var(--border) !important; }
.ui.basic.label { background: transparent !important; }

/* group type icons keep their accent colors */
.group-list-item .icon.purple { color: #b07cc6 !important; }
.group-list-item .icon.blue { color: var(--blue) !important; }
.group-list-item .icon.green { color: var(--green) !important; }

/* grid inside modals: kill fomantic negative margins overflow */
.ui.modal .ui.grid { margin: 0 !important; }
.ui.modal .ui.grid > .column { padding: .5rem !important; }

/* user info entries in modal */
.user-entry { padding: 10px 0; border-bottom: 1px dashed var(--border); font-size: .88rem; }
.user-entry:last-child { border-bottom: none; }
.user-avatar { max-width: 180px; border-radius: 14px; }

/* responsive modals */
@media (max-width: 768px) {
  .ui.modal { width: 95% !important; margin: 0 !important; }
  .ui.modal > .content { max-height: 65vh; overflow-y: auto !important; }
  .ui.modal .actions .ui.fluid.buttons { flex-direction: column; }
}

/* Objetivos táctiles de la capa Fomantic. Sólo en anchos de teléfono: en escritorio la
   píldora de 36px es la del sistema de diseño y no hay dedo que la falle.
   Los botones de los modales medían 36px y el aspa de cerrar 36x36, los dos por debajo
   del mínimo de 44. min-height por sí solo no basta en un inline-block —el texto se
   quedaría pegado arriba—, así que van con inline-flex y centrado. El padding
   horizontal lo sigue poniendo la regla de arriba, que lleva !important. */
@media (max-width: 640px) {
  .ui.button,
  .ui.mini.button,
  .ui.small.buttons .button {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .ui.modal > .close.icon {
    width: 44px; height: 44px;
    display: grid; place-items: center;
  }
  /* Con el modal casi a pantalla completa, 65vh de contenido deja el formulario en una
     rendija con la cabecera y el pie ocupando el resto. */
  .ui.modal > .content { max-height: 72vh; }
}

/* Red contra el desplazamiento horizontal — `clip`, nunca `hidden`.
   Aquí decía `html,body{max-width:100%;overflow-x:hidden}`. El `hidden` tenía un efecto
   que no se veía y sí se medía: cuando html y body dejan de ser `visible`, el navegador
   convierte a body en su propio contenedor de desplazamiento, y el dashboard entero
   pasaba a desplazarse DENTRO de body. Medido a 360px: body.scrollTop llegaba a 417 con
   window.scrollY clavado en 0 y html.scrollHeight igual al viewport. Con la página sin
   desplazarse se van window.scrollTo, scrollIntoView contra la ventana y el colapso de
   la barra de direcciones del navegador móvil, que va atado al scroll de la página.
   `clip` recorta igual pero no crea contenedor de desplazamiento: la página vuelve a ser
   la que se desplaza (window.scrollY=427) y position:sticky de la barra se conserva.
   Va en esta hoja y no en wz.css a propósito: wz.css la cargan trece páginas y
   /api/swagger.html sí desborda de verdad; recortar allí escondería su contenido en vez
   de arreglarlo. Las otras cinco del panel miden cero desbordamiento sin red ninguna. */
html, body { overflow-x: clip; }

/* ---------- pestañas del dashboard de sesión (#683) ----------
   Mismo aspecto que las del panel de administración: son la misma consola y
   dos barras de pestañas distintas se leen como dos productos. */
.tabs { display: flex; gap: 6px; margin: 22px 0 0; flex-wrap: wrap; border-bottom: 1px solid var(--border); }
.tab {
  background: transparent; border: 1px solid transparent; border-bottom: 0;
  border-radius: 10px 10px 0 0; padding: 10px 18px; color: var(--muted);
  font-size: .88rem; font-weight: 600; position: relative; top: 1px; cursor: pointer;
}
.tab:hover { color: var(--text); }
.tab[aria-selected="true"] { color: var(--green); border-color: var(--border); background: var(--card); border-bottom: 1px solid var(--card); }
.tab .tab-badge { margin-left: 8px; font-size: .7rem; color: var(--red); font-family: "JetBrains Mono", monospace; }
.tab-panel { padding-top: 22px; }

/* ---------- tabla de ajustes autogenerada (#683) ----------
   Una fila por clave del catálogo. La rejilla es de tres columnas —nombre,
   control, procedencia— y colapsa a una sola en pantalla estrecha: la columna
   de procedencia es la que dice si el valor lo puso esta sesión o es el
   default, y esconderla convertiría la pantalla en una lista de valores sin
   contexto. */
.settings-head { display: flex; gap: 16px; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; margin-bottom: 14px; }
.settings-head h3 { margin: 0 0 4px; }
.settings-head .sub { margin: 0; }
.settings-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.settings-search { margin-bottom: 12px; }
.settings-search .input { width: 100%; max-width: 360px; }
.settings-body { display: flex; flex-direction: column; gap: 2px; }
.set-group { margin-top: 18px; }
.set-group:first-child { margin-top: 0; }
.set-group-toggle {
  display: flex; align-items: center; gap: 8px; width: 100%; margin: 0 0 8px;
  background: none; border: 0; padding: 0; cursor: pointer; text-align: left;
}
.set-group-toggle > h4 {
  margin: 0; font-size: .7rem; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--muted);
}
.set-group-caret {
  width: 0; height: 0; flex: none;
  border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-top: 5px solid var(--muted); transition: transform .12s ease;
}
.set-group-cerrado .set-group-caret { transform: rotate(-90deg); }
.set-group-count { color: var(--muted); font-size: .68rem; }
.set-group-cerrado .set-group-rows { display: none; }
.set-row {
  display: grid; grid-template-columns: minmax(180px, 1.2fr) minmax(160px, 1fr) minmax(140px, .9fr);
  gap: 12px; align-items: center; padding: 10px 0; border-top: 1px solid var(--border);
}
.set-row:first-of-type { border-top: 0; }
.set-key { font-family: "JetBrains Mono", monospace; font-size: .8rem; word-break: break-all; }
.set-note { display: block; color: var(--muted); font-size: .72rem; margin-top: 4px; line-height: 1.4; }
.set-row input[type="text"], .set-row input[type="number"], .set-row select {
  width: 100%; background: var(--bg); color: var(--text);
  border: 1px solid var(--border); border-radius: 8px; padding: 7px 10px; font-size: .82rem;
}
.set-row input[type="checkbox"] { width: 18px; height: 18px; accent-color: var(--green); }
.set-row.set-readonly .set-value { color: var(--muted); font-size: .8rem; }
.set-origin { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.set-origin .set-default { color: var(--muted); font-size: .72rem; font-family: "JetBrains Mono", monospace; }
.set-row.set-off { display: none; }
@media (max-width: 720px) {
  .set-row { grid-template-columns: 1fr; }
  .set-origin { justify-content: flex-start; }
}
