  :root{
    --bg:#0f1115; --card:#181b22; --linha:#262b35; --texto:#e7e9ee;
    --fraco:#9aa3b2; --acento:#3b82f6; --ok:#22c55e; --erro:#ef4444;
  }
  *{box-sizing:border-box}
  body{margin:0;background:var(--bg);color:var(--texto);
    font:16px/1.5 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
    -webkit-text-size-adjust:100%}
  .wrap{max-width:560px;margin:0 auto;padding:16px}
  header{display:flex;align-items:center;justify-content:space-between;
    gap:12px;padding:4px 0 16px;border-bottom:1px solid var(--linha);margin-bottom:16px}
  h1{font-size:17px;margin:0;font-weight:600;letter-spacing:.2px}
  .quem{color:var(--fraco);font-size:13px}
  .card{background:var(--card);border:1px solid var(--linha);border-radius:12px;padding:16px}
  label{display:block;font-size:13px;color:var(--fraco);margin:12px 0 6px}
  input[type=text],input[type=password]{width:100%;padding:12px;border-radius:8px;
    border:1px solid var(--linha);background:#11141a;color:var(--texto);font-size:16px}
  input:focus{outline:2px solid var(--acento);outline-offset:1px}
  button{font:inherit;cursor:pointer;border:0;border-radius:8px}
  .primario{width:100%;padding:13px;background:var(--acento);color:#fff;
    font-weight:600;font-size:16px;margin-top:18px}
  .aviso{margin-top:14px;padding:10px 12px;border-radius:8px;font-size:14px;
    background:rgba(239,68,68,.12);border:1px solid rgba(239,68,68,.35);color:#fca5a5}
  .link{background:none;color:var(--fraco);font-size:13px;padding:4px;text-decoration:underline}
  @media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}
.video{position:relative;background:#000;border:1px solid var(--linha);
  border-radius:12px;overflow:hidden;aspect-ratio:16/9;margin-bottom:16px}
video-stream{display:block;width:100%;height:100%}
video-stream video{width:100%;height:100%;object-fit:contain;background:#000}
.abrir{width:100%;padding:26px;font-size:21px;font-weight:700;letter-spacing:.3px;
  background:var(--acento);color:#fff;transition:background .15s,transform .06s}
.abrir:active{transform:scale(.99)}
.abrir[disabled]{background:#2b3442;color:var(--fraco);cursor:not-allowed}
.abrir.ok{background:var(--ok)}
.abrir.falhou{background:var(--erro)}
.estado{min-height:22px;margin-top:12px;font-size:14px;color:var(--fraco);text-align:center}
.rodape{display:flex;justify-content:space-between;align-items:center;
  margin-top:22px;padding-top:14px;border-top:1px solid var(--linha)}
.sair{margin:0}

/* O <video-stream> do go2rtc injeta o proprio CSS por innerHTML, e o CSP
   (style-src 'self', sem unsafe-inline) bloqueia esse <style>. Sem ele o
   .info perde position/cor e a mensagem de erro do player fica preta sobre
   fundo escuro, fora de lugar: existe no DOM e ninguem ve.
   Reproduzimos as regras aqui, servidas como arquivo, para o CSP continuar
   fechado numa pagina que abre uma porta fisica. */
video-stream { position: relative; }
video-stream .info {
  position: absolute; top: 0; left: 0; right: 0;
  padding: 10px 12px;
  display: flex; justify-content: space-between; gap: 8px;
  color: #fff; font-size: 13px; line-height: 1.35;
  text-shadow: 0 1px 3px rgba(0,0,0,.9);
  pointer-events: none;
}
video-stream .status { flex: 1; word-break: break-word; }
video-stream .mode { flex: 0 0 auto; opacity: .85; text-transform: uppercase;
  letter-spacing: .5px; font-variant-numeric: tabular-nums; }
/* Espelho do estado do player, fora do componente: sobrevive mesmo que o
   layout interno falhe. */
.diag { margin-top: 10px; font-size: 13px; color: var(--fraco);
  background: #11141a; border: 1px solid var(--linha); border-radius: 8px;
  padding: 10px 12px; display: none; }
.diag.mostrando { display: block; }
.diag b { color: var(--texto); font-weight: 600; }
.diag code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px; color: #fca5a5; word-break: break-all; }
