/* ============================================================
   Cuiudo Lurker — sistema visual do painel
   Dark, com acento verde do Kick. Todos os ids/classes usados por
   app.js e pelo launcher são preservados. NÃO usar transform/filter
   em .grade/.slot/.slot-chat: o launcher desenha o vídeo por cima
   dessas coordenadas e qualquer deslocamento CSS desalinha.

   Regra do sistema: nenhum valor de espaço, tamanho de fonte, sombra
   ou duração é escrito à mão. Tudo sai dos tokens abaixo. Um valor
   solto no meio do arquivo é dívida — foi o que deixou o painel cru.
   ============================================================ */

:root {
    /* ---------- superfícies (do fundo para a frente) ---------- */
    --bg:        #08080e;
    --surface-1: #101017;
    --surface-2: #171720;
    --surface-3: #1f1f2b;
    --surface-4: #2a2a38;   /* topo da pilha: hover de superfície elevada */

    /* ---------- texto ---------- */
    --fg:      #ededf3;
    --fg-dim:  #9c9cb0;
    /* Era #6c6c7e: ~3.4:1 sobre --surface-2, reprovava em AA — e era justamente
       a cor dos rótulos minúsculos do HUD. Agora ~5.1:1. */
    --fg-mute: #8a8a9e;

    /* ---------- acentos de marca ---------- */
    --kick:     #53fc18;
    --kick-2:   #43d80f;
    --amarelo:  #f7d64e;
    --vermelho: #ff5060;
    --verde:    #3dff6a;

    /* ---------- semânticos ----------
       Componente pede significado, não cor de marca. Trocar o tom de perigo
       aqui muda o app inteiro, sem caçar rgba() espalhado. */
    --ok:     var(--verde);
    --aviso:  var(--amarelo);
    --perigo: var(--vermelho);

    /* ---------- linhas ---------- */
    --borda:       #2a2a38;
    --borda-forte: #3a3a4a;   /* borda em hover / estado */
    --borda-soft:  rgba(255,255,255,.06);

    /* ---------- espaçamento ----------
       Painel desktop denso: passo de 4px até 16, depois salta. */
    --s-1:  4px;
    --s-2:  8px;
    --s-3: 12px;
    --s-4: 16px;
    --s-5: 24px;
    --s-6: 32px;
    --s-7: 48px;

    /* ---------- tipografia ---------- */
    --t-2xs: 11px;   /* rótulo em caixa alta — o piso legível */
    --t-xs:  12px;
    --t-sm:  13px;
    --t-md:  14px;   /* base */
    --t-lg:  16px;
    --t-xl:  20px;
    --t-2xl: 26px;

    --w-reg:   400;
    --w-med:   500;
    --w-semi:  600;
    --w-bold:  700;
    --w-black: 800;

    /* Caixa alta só com tracking; sem ele vira um borrão. */
    --track-rotulo: .5px;

    /* ---------- geometria ---------- */
    --r:    12px;
    --r-sm:  8px;
    --r-xs:  6px;

    /* ---------- elevação ----------
       Superfície mais alta = sombra maior. Nunca uma sombra avulsa. */
    --sh-0: 0 0 0 1px var(--borda);
    --sh-1: 0 1px 2px rgba(0,0,0,.4);
    --sh-2: 0 6px 20px rgba(0,0,0,.45);
    --sh-3: 0 18px 50px rgba(0,0,0,.6);

    /* ---------- glow ----------
       O verde brilha para marcar ESTADO (foco, plano ativo), nunca para
       decorar. Se dois elementos brilham na mesma tela, um deles está errado. */
    --glow-kick-soft: 0 0 0 3px rgba(83,252,24,.15);
    --glow-kick:      0 0 0 1px rgba(83,252,24,.35), 0 6px 24px rgba(83,252,24,.12);

    /* ---------- movimento ---------- */
    --dur-1: 120ms;
    --dur-2: 180ms;
    --dur-3: 260ms;
    --ease-out: cubic-bezier(.16, 1, .3, 1);
    --ease-in:  cubic-bezier(.4, 0, 1, 1);

    /* ---------- gradientes ---------- */
    --grad-kick: linear-gradient(180deg, #63ff30 0%, #45e00f 100%);
    --grad-surface: linear-gradient(180deg, rgba(255,255,255,.03), rgba(255,255,255,0));
    --grad-topo: linear-gradient(180deg, #0d0d14, #0a0a10);

    /* ---------- ícones (mask SVG; nenhum emoji, nenhum caractere) ---------- */
    --ico-olho: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='M12 5c-5 0-9 4.5-10 7 1 2.5 5 7 10 7s9-4.5 10-7c-1-2.5-5-7-10-7Zm0 11a4 4 0 1 1 0-8 4 4 0 0 1 0 8Zm0-2a2 2 0 1 0 0-4 2 2 0 0 0 0 4Z'/%3E%3C/svg%3E");
    --ico-olho-corte: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='M2.1 3.5 3.5 2.1l18.4 18.4-1.4 1.4-3.3-3.3A11.6 11.6 0 0 1 12 19c-5 0-9-4.5-10-7a13.6 13.6 0 0 1 4.2-5.3L2.1 3.5Zm5.5 5.5A4 4 0 0 0 12 16a4 4 0 0 0 1.4-.3l-1.6-1.6a2 2 0 0 1-2.5-2.5L7.6 9ZM12 5c5 0 9 4.5 10 7a13.9 13.9 0 0 1-3 4l-3-3a4 4 0 0 0-5-5L8.7 5.7A11.6 11.6 0 0 1 12 5Z'/%3E%3C/svg%3E");
    --ico-moeda: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20Zm0 18a8 8 0 1 1 0-16 8 8 0 0 1 0 16Zm.9-12.5H10v9h1.9v-3H13a3 3 0 0 0 0-6Zm.1 4h-1.1v-2H13a1 1 0 0 1 0 2Z'/%3E%3C/svg%3E");
    --ico-relogio: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20Zm0 18a8 8 0 1 1 0-16 8 8 0 0 1 0 16Zm1-13h-2v6l5 3 1-1.7-4-2.3V7Z'/%3E%3C/svg%3E");
    --ico-passe: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='M4 6h16a2 2 0 0 1 2 2v2a2 2 0 0 0 0 4v2a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-2a2 2 0 0 0 0-4V8a2 2 0 0 1 2-2Zm11 2v8h2V8h-2Z'/%3E%3C/svg%3E");
    --ico-alerta: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='M12 2 1 21h22L12 2Zm0 4.5L19.5 19h-15L12 6.5ZM11 10v5h2v-5h-2Zm0 6v2h2v-2h-2Z'/%3E%3C/svg%3E");
    --ico-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2Z'/%3E%3C/svg%3E");
    --ico-x: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='m19 6.4-1.4-1.4-5.6 5.6-5.6-5.6L5 6.4l5.6 5.6L5 17.6 6.4 19l5.6-5.6 5.6 5.6 1.4-1.4-5.6-5.6L19 6.4Z'/%3E%3C/svg%3E");
}

* { box-sizing: border-box; }

/* O `hidden` vem da folha do NAVEGADOR e perde para qualquer regra de autor que
   declare display — e o app.js esconde meio painel por `.hidden`. Sem isto, o
   `display:block` de `.caixa-passe label` reacendia o seletor "se não couber"
   (que o app.js esconde de quem tem janela 1, o free) e o bloco reaparecia. */
[hidden] { display: none !important; }

html, body {
    margin: 0;
    height: 100%;
    background: var(--bg);
    color: var(--fg);
    font-family: "Segoe UI Variable", "Segoe UI", system-ui, -apple-system, sans-serif;
    font-size: var(--t-md);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

/* Esconde a barra de rolagem do documento (o app é tela cheia);
   os containers roláveis internos ganham uma barra fininha própria. */
html, body { scrollbar-width: none; -ms-overflow-style: none; }
html::-webkit-scrollbar, body::-webkit-scrollbar { width: 0; height: 0; display: none; }

a { color: var(--kick); text-decoration: none; }
a:hover { text-decoration: underline; }

::selection { background: rgba(83,252,24,.28); }

/* Barra de rolagem fininha para as áreas que rolam */
.grade, .planos, .admin-corpo, #modal-config {
    scrollbar-width: thin;
    scrollbar-color: #33333f transparent;
}
.grade::-webkit-scrollbar, .planos::-webkit-scrollbar,
.admin-corpo::-webkit-scrollbar { width: 10px; height: 10px; }
.grade::-webkit-scrollbar-thumb, .planos::-webkit-scrollbar-thumb,
.admin-corpo::-webkit-scrollbar-thumb {
    background: #30303d; border-radius: 10px;
    border: 3px solid transparent; background-clip: content-box;
}
.grade::-webkit-scrollbar-thumb:hover, .planos::-webkit-scrollbar-thumb:hover,
.admin-corpo::-webkit-scrollbar-thumb:hover { background: #43434f; background-clip: content-box; }

/* Utilitário de ícone: todo ícone do app é um mask SVG pintado por
   background-color, então herda a cor do estado sem virar outro arquivo. */
.ico {
    display: inline-block; flex: 0 0 auto;
    width: 16px; height: 16px;
    background: currentColor;
    -webkit-mask-position: center; mask-position: center;
    -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
    -webkit-mask-size: contain; mask-size: contain;
}

/* =========================================================
   Botões (sistema unificado)
   ========================================================= */
.btn-primario, .btn-assinar, .btn-mini-kick {
    display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
    border: 0; border-radius: var(--r-sm); cursor: pointer;
    background: var(--grad-kick); color: #06140a;
    font-family: inherit; font-size: var(--t-md); font-weight: var(--w-bold);
    box-shadow: var(--sh-1);
    transition: filter var(--dur-2) var(--ease-out),
                box-shadow var(--dur-2) var(--ease-out),
                transform var(--dur-1) var(--ease-out);
}
.btn-primario { width: 100%; padding: var(--s-3) var(--s-4); }
.btn-primario:hover, .btn-assinar:hover, .btn-mini-kick:hover {
    filter: brightness(1.06);
    box-shadow: 0 4px 16px rgba(83,252,24,.25);
}
.btn-primario:active, .btn-assinar:active, .btn-mini-kick:active { transform: translateY(1px); }

button:disabled {
    opacity: .5; cursor: not-allowed;
    filter: none !important; box-shadow: none; transform: none !important;
}

.btn-sec {
    display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
    padding: var(--s-3) var(--s-4); border-radius: var(--r-sm);
    border: 1px solid var(--borda); background: var(--surface-3); color: var(--fg);
    font-family: inherit; font-size: var(--t-md); font-weight: var(--w-semi); cursor: pointer;
    transition: border-color var(--dur-2) var(--ease-out),
                background var(--dur-2) var(--ease-out);
}
.btn-sec:hover { border-color: var(--borda-forte); background: var(--surface-4); }

:focus-visible {
    outline: 2px solid var(--kick);
    outline-offset: 2px;
}

/* =========================================================
   Telas de login / cadastro / retorno do Stripe
   ========================================================= */
.tela-auth, .tela-connect {
    display: flex; align-items: center; justify-content: center;
    min-height: 100vh; padding: var(--s-5);
    background:
        radial-gradient(1200px 600px at 50% -10%, rgba(83,252,24,.10), transparent 60%),
        radial-gradient(800px 500px at 90% 110%, rgba(83,252,24,.06), transparent 55%),
        var(--bg);
}
/* Um cancelamento não se comemora em verde: mesmo card, fundo sem a marca. */
.tela-neutra {
    display: flex; align-items: center; justify-content: center;
    min-height: 100vh; padding: var(--s-5);
    background:
        radial-gradient(1000px 560px at 50% -10%, rgba(255,255,255,.04), transparent 60%),
        var(--bg);
}

.card-auth {
    width: 100%; max-width: 400px;
    background: var(--surface-2); background-image: var(--grad-surface);
    border: 1px solid var(--borda); border-radius: var(--r);
    padding: var(--s-6) var(--s-5);
    box-shadow: var(--sh-3);
    text-align: center;
}
/* A marca é assinatura, não título: fica acima, discreta. O <h1> é a tarefa. */
.card-marca {
    display: flex; flex-direction: column; align-items: center; gap: var(--s-2);
    margin-bottom: var(--s-4);
}
.card-marca .marca-mark { width: 56px; height: 56px; border-radius: var(--r); }
.card-marca-nome {
    font-size: var(--t-2xs); font-weight: var(--w-bold); color: var(--fg-mute);
    text-transform: uppercase; letter-spacing: var(--track-rotulo);
}
.card-auth h1 {
    margin: 0 0 var(--s-1);
    font-size: var(--t-xl); font-weight: var(--w-black); letter-spacing: -.2px;
}
.card-auth form { text-align: left; margin-top: var(--s-5); }
.sub { margin: 0 0 var(--s-5); color: var(--fg-dim); font-size: var(--t-sm); }

/* Rótulo de campo: caixa alta, pequeno, apagado. O .switch-linha fica de fora —
   ele também é um <label>, mas o texto dele é o ESTADO ("Estou ao vivo"), não o
   nome de um campo. Sem o :not(), esta regra (0,2,0) vencia o reset do switch. */
.card-auth label, .form-config label, .caixa-passe label:not(.switch-linha) {
    display: block; margin-bottom: var(--s-4);
    font-size: var(--t-2xs); font-weight: var(--w-semi); color: var(--fg-dim);
    text-transform: uppercase; letter-spacing: var(--track-rotulo);
}

/* Campos de texto: um só visual em todo o app.
   O :not() não é firula — sem ele este seletor (0,2,0) vence o .switch (0,1,0) e
   estica o checkbox do "estou ao vivo" para width:100% + padding, virando um
   trilho de 222px. Checkbox não é campo de texto. */
.card-auth input:not([type="checkbox"]),
.form-config input:not([type="checkbox"]),
.caixa-passe input:not([type="checkbox"]),
.caixa-passe select {
    width: 100%; margin-top: var(--s-2);
    padding: var(--s-3);
    background: var(--surface-1); border: 1px solid var(--borda);
    border-radius: var(--r-sm); color: var(--fg);
    font-family: inherit; font-size: var(--t-md);
    transition: border-color var(--dur-2) var(--ease-out),
                box-shadow var(--dur-2) var(--ease-out);
}
.card-auth input::placeholder, .form-config input::placeholder,
.caixa-passe input::placeholder { color: var(--fg-mute); }
.card-auth input:not([type="checkbox"]):focus,
.form-config input:not([type="checkbox"]):focus,
.caixa-passe input:not([type="checkbox"]):focus,
.caixa-passe select:focus {
    outline: none; border-color: var(--kick);
    box-shadow: var(--glow-kick-soft);
}
.card-auth .btn-primario { margin-top: var(--s-1); }

/* Senha com botão de exibir: o olho vive DENTRO do campo. */
.campo-senha { position: relative; display: block; }
.campo-senha input { padding-right: var(--s-7); }
.btn-olho {
    position: absolute; right: var(--s-1); bottom: var(--s-1);
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px;
    border: 0; border-radius: var(--r-xs); background: transparent;
    color: var(--fg-mute); cursor: pointer;
    transition: color var(--dur-2) var(--ease-out);
}
.btn-olho:hover { color: var(--fg); }
.btn-olho .ico { -webkit-mask-image: var(--ico-olho); mask-image: var(--ico-olho); }
.btn-olho[aria-pressed="true"] .ico {
    -webkit-mask-image: var(--ico-olho-corte); mask-image: var(--ico-olho-corte);
}

.troca-modo {
    margin-top: var(--s-5); text-align: center;
    font-size: var(--t-sm); color: var(--fg-dim);
}

/* Marca (logo + nome) */
.marca-mark {
    width: 30px; height: 30px; border-radius: 9px;
    background: url('logo.png') center/contain no-repeat; display: inline-block;
    flex: 0 0 auto;
}

/* Ícone grande da página de retorno do Stripe (era <style> inline no PHP). */
.pg-icone {
    width: 64px; height: 64px; margin: 0 auto var(--s-5); border-radius: 50%;
    display: grid; place-items: center;
}
.pg-icone .ico { width: 30px; height: 30px; }
.pg-ok     { background: rgba(83,252,24,.15); color: var(--kick); }
.pg-neutro { background: rgba(154,154,176,.15); color: var(--fg-dim); }
.pg-ok     .ico { -webkit-mask-image: var(--ico-check); mask-image: var(--ico-check); }
.pg-neutro .ico { -webkit-mask-image: var(--ico-x);     mask-image: var(--ico-x); }

/* =========================================================
   Avisos e mensagens
   ========================================================= */
.alerta, .aviso-ok, .promo-bonus {
    display: flex; align-items: flex-start; gap: var(--s-2);
    padding: var(--s-3); border-radius: var(--r-sm);
    font-size: var(--t-sm); line-height: 1.5;
    margin-bottom: var(--s-4); text-align: left;
}
.alerta {
    background: rgba(255,80,96,.12); border: 1px solid rgba(255,80,96,.5);
    color: #ffb8bf;
}
.aviso-ok {
    background: rgba(61,255,106,.1); border: 1px solid rgba(61,255,106,.45);
    color: #bfffce;
}
/* Aviso de promoção (bônus de cadastro): âmbar, com a moeda de ícone. */
.promo-bonus {
    background: rgba(247,214,78,.1); border: 1px solid rgba(247,214,78,.45);
    color: #ffeaa3;
}
.alerta::before, .aviso-ok::before, .promo-bonus::before {
    content: ""; width: 16px; height: 16px; flex: 0 0 auto; margin-top: 2px;
    background: currentColor;
    -webkit-mask-position: center; mask-position: center;
    -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
    -webkit-mask-size: contain; mask-size: contain;
}
.alerta::before      { -webkit-mask-image: var(--ico-alerta); mask-image: var(--ico-alerta); }
.aviso-ok::before    { -webkit-mask-image: var(--ico-check);  mask-image: var(--ico-check); }
.promo-bonus::before { -webkit-mask-image: var(--ico-moeda);  mask-image: var(--ico-moeda); }

/* =========================================================
   Painel principal — barra de topo
   ========================================================= */
.tela-lurk { display: flex; flex-direction: column; height: 100vh; overflow: hidden; }

.barra-topo {
    display: flex; align-items: center; gap: var(--s-3);
    padding: var(--s-2) var(--s-4); flex: 0 0 auto;
    background: var(--grad-topo);
    border-bottom: 1px solid var(--borda);
}
.marca {
    display: inline-flex; align-items: center; gap: var(--s-2);
    font-size: var(--t-lg); font-weight: var(--w-black); letter-spacing: -.2px;
}
.marca .marca-mark { width: 28px; height: 28px; border-radius: var(--r-sm); }
.espaco { flex: 1; }

/* Badge de conexão como pílula com bolinha */
.status-conexao {
    display: inline-flex; align-items: center; gap: var(--s-2);
    font-size: var(--t-2xs); font-weight: var(--w-semi);
    padding: var(--s-1) var(--s-3) var(--s-1) var(--s-2);
    border-radius: 999px; border: 1px solid var(--borda); background: var(--surface-2);
    color: var(--fg-dim);
}
.status-conexao::before {
    content: ""; width: 7px; height: 7px; border-radius: 50%;
    background: currentColor; box-shadow: 0 0 8px currentColor;
}
.status-conexao[data-state="connected"]    { color: var(--ok);     border-color: rgba(61,255,106,.35); }
.status-conexao[data-state="reconnecting"] { color: var(--aviso);  border-color: rgba(247,214,78,.35); }
.status-conexao[data-state="disconnected"] { color: var(--perigo); border-color: rgba(255,80,96,.35); }

/* ---------- Botões da barra ----------
   Antes tudo era .btn-sair (inclusive "Admin" e "Voltar ao painel"): a classe
   mentia e três pesos de ação tinham o mesmo visual. Agora: .btn-topo é o
   neutro, e .btn-sair é só o sair de verdade — separado por uma divisória. */
.barra-topo .btn-topo, .barra-topo .btn-config, .btn-sair {
    display: inline-flex; align-items: center; gap: var(--s-2);
    padding: var(--s-2) var(--s-3); border-radius: var(--r-sm);
    font-family: inherit; font-size: var(--t-sm); font-weight: var(--w-semi);
    cursor: pointer; border: 1px solid var(--borda); background: var(--surface-2);
    color: var(--fg); text-decoration: none;
    transition: border-color var(--dur-2) var(--ease-out),
                background var(--dur-2) var(--ease-out),
                color var(--dur-2) var(--ease-out);
}
.barra-topo .btn-topo:hover, .barra-topo .btn-config:hover {
    border-color: var(--borda-forte); background: var(--surface-3); text-decoration: none;
}
/* Mudo do app. O estado "mudo" é o normal (o launcher nasce assim), então quem
   ganha destaque é o som LIGADO — é ele que o usuário precisa achar rápido
   quando as lives começam a falar todas juntas. */
.barra-topo .btn-mudo { min-width: 8.5rem; justify-content: center; color: var(--fg-mute); }
.barra-topo .btn-mudo-ativo {
    color: var(--fg); border-color: var(--borda-forte); background: var(--surface-3);
}

/* Sair é saída, não ação do painel: fica apagado e só se acende no hover. */
.btn-sair {
    background: transparent; border-color: transparent; color: var(--fg-mute);
}
.btn-sair:hover {
    background: rgba(255,80,96,.1); border-color: rgba(255,80,96,.35);
    color: #ff9aa2; text-decoration: none;
}
.barra-divisor {
    width: 1px; height: 24px; flex: 0 0 auto;
    background: var(--borda); margin: 0 var(--s-1);
}

/* ---------- HUD (chips de status) ---------- */
.hud { display: flex; align-items: center; gap: var(--s-2); }
.hud-item {
    display: flex; align-items: center; gap: var(--s-2);
    height: 40px; padding: 0 var(--s-3);
    border-radius: var(--r-sm);
    background: var(--surface-2); border: 1px solid var(--borda);
}
.hud-item::before {
    content: ""; width: 16px; height: 16px; flex: 0 0 auto;
    background: var(--fg-dim);
    -webkit-mask-position: center; mask-position: center;
    -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
    -webkit-mask-size: contain; mask-size: contain;
}
.hud-moedas::before {
    background: var(--amarelo);
    -webkit-mask-image: var(--ico-moeda); mask-image: var(--ico-moeda);
}
.hud-ciclo::before {
    background: var(--kick);
    -webkit-mask-image: var(--ico-relogio); mask-image: var(--ico-relogio);
}
.hud-passe-item::before {
    background: var(--kick);
    -webkit-mask-image: var(--ico-passe); mask-image: var(--ico-passe);
}

.hud-texto { display: flex; flex-direction: column; justify-content: center; line-height: 1.2; }
.hud-rotulo {
    color: var(--fg-mute); text-transform: uppercase;
    letter-spacing: var(--track-rotulo);
    font-size: var(--t-2xs); font-weight: var(--w-bold);
}
.hud-item strong {
    font-size: var(--t-lg); font-weight: var(--w-bold);
    font-variant-numeric: tabular-nums;
}
#hud-saldo { color: var(--amarelo); }
#hud-passe { color: var(--kick); }

.hud-ciclo { min-width: 168px; }
.barra-ciclo {
    flex: 1; height: 6px; border-radius: 999px; background: #0c0c12;
    border: 1px solid var(--borda); overflow: hidden;
}
.barra-ciclo > div {
    height: 100%; width: 0; border-radius: 999px;
    background: var(--grad-kick); box-shadow: 0 0 10px rgba(83,252,24,.5);
    transition: width .5s var(--ease-out);
}
.hud-ciclo small {
    color: var(--fg-dim); min-width: 32px; text-align: right;
    font-size: var(--t-xs); font-variant-numeric: tabular-nums;
}

/* Banner de conta Kick desconectada. É ELE que carrega o CTA verde quando a
   conta não está conectada — por isso o botão da barra de topo é secundário. */
.aviso-kick {
    flex: 0 0 auto; display: flex; align-items: center; gap: var(--s-3);
    padding: var(--s-3) var(--s-4); font-size: var(--t-sm);
    background: linear-gradient(180deg, rgba(247,214,78,.14), rgba(247,214,78,.07));
    border-bottom: 1px solid rgba(247,214,78,.4);
    color: #f8e9ac;
}
.aviso-kick .ico { color: var(--amarelo); -webkit-mask-image: var(--ico-alerta); mask-image: var(--ico-alerta); }
.btn-mini-kick {
    margin-left: auto; padding: var(--s-2) var(--s-3);
    font-size: var(--t-sm); white-space: nowrap;
}

/* DoubleCoins: barra dourada, chamativa, no topo do painel. app.js liga/desliga. */
.banner-double {
    flex: 0 0 auto;
    display: flex; align-items: center; justify-content: center; gap: var(--s-3);
    padding: var(--s-3) var(--s-4);
    font-size: var(--t-sm); font-weight: 600; text-align: center;
    color: #2a1e00;
    background: linear-gradient(100deg, #b8860b, #ffd84a 30%, #fff3b0 50%, #ffd84a 70%, #b8860b);
    background-size: 200% 100%;
    border-bottom: 1px solid rgba(255,216,74,.6);
    box-shadow: 0 2px 18px rgba(255,216,74,.35);
    animation: brilho-double 3s linear infinite;
}
.banner-double[hidden] { display: none; }  /* vence o display:flex acima */
.banner-double strong { font-weight: 800; }
.banner-double-ico { font-size: 1.25em; animation: pulso-double 1.4s ease-in-out infinite; }
@keyframes brilho-double { from { background-position: 0% 50%; } to { background-position: 200% 50%; } }
@keyframes pulso-double { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.28); } }
@media (prefers-reduced-motion: reduce) {
    .banner-double, .banner-double-ico { animation: none; }
}

/* Aviso de atualização do launcher. Deliberadamente MENOS chamativo que o
   DoubleCoins: é recado utilitário, não promoção — não pode competir com o
   banner dourado nem parecer propaganda, senão vira ruído e ninguém atualiza. */
.banner-atualizar {
    flex: 0 0 auto;
    display: flex; align-items: center; justify-content: center; gap: var(--s-3);
    padding: var(--s-3) var(--s-4);
    font-size: var(--t-sm); text-align: center;
    color: var(--fg); background: var(--surface-3);
    border-bottom: 1px solid var(--borda);
}
.banner-atualizar[hidden] { display: none; }  /* vence o display:flex acima */
.banner-atualizar-ico { font-size: 1.1em; }
.btn-atualizar {
    flex: 0 0 auto;
    padding: var(--s-2) var(--s-4); border-radius: var(--r-sm);
    background: var(--verde); color: #06210a;
    font-size: var(--t-sm); font-weight: var(--w-bold); text-decoration: none;
    white-space: nowrap;
}
.btn-atualizar:hover { filter: brightness(1.08); }

/* Alerta CENTRAL de atualização.
   Cobre a tela e não tem como fechar, de propósito: a partir do 4.4.0 a versão
   antiga não reserva horário, então um aviso que dá para dispensar viraria uma
   recusa inexplicada na hora de reservar.

   O z-index NÃO basta para ficar por cima das lives: os players são janelas
   NATIVAS do WebView2 sobrepostas ao painel, fora do fluxo do CSS. Quem os
   empurra para trás é o manterAlertaVisivel() no app.js, mandando kick_chat_back
   — e ele precisa reafirmar isso a cada refresh da vitrine, porque todo layout
   novo devolve os players para a frente. */
.overlay-atualizar {
    position: fixed; inset: 0; z-index: 200;
    display: flex; align-items: center; justify-content: center;
    padding: var(--s-4);
    background: rgba(7, 7, 12, .82);
    backdrop-filter: blur(3px);
}
.overlay-atualizar[hidden] { display: none; }
.overlay-atualizar-caixa {
    width: min(560px, 100%);
    padding: var(--s-6) var(--s-5);
    text-align: center;
    background: var(--surface-2);
    border: 1px solid var(--borda-forte);
    border-radius: var(--r-sm);
    box-shadow: 0 24px 64px rgba(0, 0, 0, .55);
}
.overlay-atualizar-ico { font-size: 2.4rem; line-height: 1; margin-bottom: var(--s-3); }
.overlay-atualizar-caixa h2 {
    margin: 0 0 var(--s-3); font-size: var(--t-lg); font-weight: var(--w-bold); color: var(--fg);
}
.overlay-atualizar-texto {
    margin: 0 0 var(--s-3); font-size: var(--t-sm); line-height: 1.55; color: var(--fg-mute);
}
/* Âmbar, não vermelho: é uma limitação temporária, não um erro da pessoa. */
.overlay-atualizar-bloqueio {
    margin: 0 0 var(--s-5); padding: var(--s-3);
    font-size: var(--t-sm); line-height: 1.5;
    color: #ffd79a; background: rgba(255, 176, 32, .1);
    border: 1px solid rgba(255, 176, 32, .3); border-radius: var(--r-sm);
}
.btn-atualizar-grande {
    display: inline-block; padding: var(--s-3) var(--s-6); font-size: var(--t-md);
}
.overlay-atualizar-passos {
    margin: var(--s-4) 0 0; font-size: var(--t-xs); color: var(--fg-mute);
}

/* =========================================================
   Corpo: grade da vitrine + lateral
   ========================================================= */
.corpo { flex: 1 1 auto; display: flex; min-height: 0; }

/* A grade NÃO rola.
   O launcher desenha os players como janelas nativas por cima das coordenadas
   que o app.js mede — e janela nativa não é recortada pelo scroll do CSS. Um
   slot rolado para fora da área visível vira player desalinhado ou preto. Por
   isso a grade sempre cabe: --cols vem do servidor/app.js (calculado a partir
   do número de slots) e as linhas dividem a altura disponível em partes iguais. */
.grade {
    flex: 1 1 auto; display: grid; gap: var(--s-2); padding: var(--s-3);
    grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr));
    grid-auto-rows: minmax(0, 1fr);
    align-content: stretch; min-height: 0;
    overflow: hidden;
}
/* Fora do launcher não há vídeo nativo para desalinhar: aí pode rolar. */
.grade.sem-launcher {
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    grid-auto-rows: min-content; align-content: start;
    overflow-y: auto;
}

.slot {
    display: flex; flex-direction: column; min-height: 0;
    border: 1px solid var(--borda); border-radius: var(--r); overflow: hidden;
    background: var(--surface-2);
    box-shadow: var(--sh-1);
    /* só cor/sombra na interação — nada de transform (desalinharia o vídeo) */
    transition: border-color var(--dur-2) var(--ease-out),
                box-shadow var(--dur-2) var(--ease-out);
}
.slot:hover { border-color: var(--borda-forte); box-shadow: var(--sh-2); }

/* Barra fina de propósito. Com 26 slots o card tem ~113px de altura: um
   cabeçalho "confortável" de 40px comia 35% dele e espremia o vídeo (que é
   16:9) a 63% da área útil. Enxuto, o vídeo passa a ocupar ~93%. */
.slot-cabecalho {
    flex: 0 0 auto; padding: var(--s-1) var(--s-3); line-height: 1.4;
    font-size: var(--t-xs); font-weight: var(--w-semi);
    background: linear-gradient(180deg, var(--surface-3), var(--surface-2));
    border-bottom: 1px solid var(--borda);
    display: flex; align-items: center; gap: var(--s-2);
    white-space: nowrap; overflow: hidden;
}
.slot-nome { overflow: hidden; text-overflow: ellipsis; color: var(--fg); }
.slot-viewers {
    margin-left: auto; flex: 0 0 auto;
    display: inline-flex; align-items: center; gap: var(--s-1);
    color: var(--kick); font-size: var(--t-2xs); font-weight: var(--w-bold);
    font-variant-numeric: tabular-nums;
    background: rgba(83,252,24,.12); border-radius: 999px;
    padding: 2px var(--s-2);
}
.slot-viewers:empty { display: none; }
.slot-viewers::before {
    content: ""; width: 12px; height: 12px; background: var(--kick);
    -webkit-mask: var(--ico-olho) center/contain no-repeat;
            mask: var(--ico-olho) center/contain no-repeat;
}
.ao-vivo {
    width: 8px; height: 8px; border-radius: 50%; background: var(--perigo);
    flex: 0 0 auto; box-shadow: 0 0 0 0 rgba(255,80,96,.6); animation: pulso 1.8s infinite;
}
@keyframes pulso {
    0%   { box-shadow: 0 0 0 0 rgba(255,80,96,.55); }
    70%  { box-shadow: 0 0 0 7px rgba(255,80,96,0); }
    100% { box-shadow: 0 0 0 0 rgba(255,80,96,0); }
}

/* ---------- A moldura do player ----------
   O .slot-chat é o retângulo que o app.js mede e o launcher pinta por cima.
   Antes ele era `width:100%; aspect-ratio:16/9` solto num flex: quando a linha
   da grade era mais baixa que cabeçalho + 16:9, o overflow:hidden do .slot
   recortava o HTML mas NÃO a janela nativa — e o vídeo vazava por cima do slot
   de baixo. Agora o .slot-midia é um container de tamanho e o .slot-chat faz
   "contain": encolhe mantendo 16:9 e nunca ultrapassa a linha.
   container-type é containment, não transform/filter/opacity: não desloca nada. */
.slot-midia {
    flex: 1 1 auto; min-height: 0;
    display: grid; place-items: center;
    /* Recuo mínimo para o vídeo (retângulo duro) não cortar o canto arredondado
       do card: para um raio r, o recuo tem que ser >= r * (1 - 1/√2). Com
       r = 12px isso dá 3,5px — daí os 4px. */
    padding: var(--s-1);
}
.slot-chat { background: #0b0b11; }

/* Dentro do launcher a linha da grade tem altura DEFINIDA (grid-auto-rows: 1fr).
   Só aí o .slot-midia pode virar container de tamanho, e o vídeo faz "contain":
   encolhe mantendo 16:9 e nunca ultrapassa a linha.
   container-type é containment — não é transform/filter/opacity, não desloca nada. */
.grade:not(.sem-launcher) .slot-midia { container-type: size; }
.grade:not(.sem-launcher) .slot-chat {
    width: min(100cqw, calc(100cqh * 16 / 9));
    aspect-ratio: 16 / 9;
}

/* Fora do launcher a linha é min-content: quem DÁ a altura é o próprio vídeo.
   Aqui `container-type: size` seria fatal — size containment manda o navegador
   ignorar o conteúdo ao medir o container, e o vídeo colapsava para 0x0. */
.grade.sem-launcher .slot-chat { width: 100%; aspect-ratio: 16 / 9; }

/* Estado vazio */
.vazio {
    grid-column: 1 / -1; align-self: center; justify-self: center;
    text-align: center; color: var(--fg-dim);
    padding: var(--s-7) var(--s-5); max-width: 380px;
}
.vazio::before {
    content: ""; display: block; width: 56px; height: 56px; margin: 0 auto var(--s-4);
    background: var(--fg-mute);
    -webkit-mask: var(--ico-olho) center/contain no-repeat;
            mask: var(--ico-olho) center/contain no-repeat;
}
.vazio p { margin: var(--s-1) 0; }
.vazio p:first-of-type {
    color: var(--fg); font-weight: var(--w-bold); font-size: var(--t-lg);
}
.vazio .btn-primario { width: auto; margin-top: var(--s-4); padding: var(--s-3) var(--s-5); }

/* Fora do launcher: placeholders neutros */
.grade.sem-launcher .slot-chat::after {
    content: "vídeo disponível no aplicativo";
    display: flex; align-items: center; justify-content: center;
    height: 100%; color: var(--fg-mute); font-size: var(--t-xs); letter-spacing: .3px;
}

/* Slot em renovação: o app.js tira o slot do layout por ~2,5s para o launcher
   recarregar o player (ver "Renovação forçada de slot"). Nesses segundos a
   janela nativa some e aparece o HTML de baixo — sem este aviso o usuário vê um
   buraco preto no meio da grade e acha que quebrou. */
.grade:not(.sem-launcher) .slot-chat.recarregando::after {
    content: "recarregando…";
    display: flex; align-items: center; justify-content: center;
    height: 100%; color: var(--fg-mute); font-size: var(--t-xs); letter-spacing: .3px;
}

/* =========================================================
   Lateral do painel
   A ordem aqui é por FREQUÊNCIA de uso: reservar é o que o usuário faz toda
   hora; escolher plano, uma vez. Por isso a fila vem antes dos planos.
   ========================================================= */
.planos {
    flex: 0 0 288px; padding: var(--s-4); overflow-y: auto;
    background: var(--surface-1); border-left: 1px solid var(--borda);
    display: flex; flex-direction: column; gap: var(--s-5);
}
.painel-secao { display: flex; flex-direction: column; gap: var(--s-3); }
/* Título de seção: rótulo, não manchete. Quem grita é o conteúdo. */
.painel-secao > h2 {
    margin: 0; font-size: var(--t-2xs); font-weight: var(--w-bold);
    color: var(--fg-mute); text-transform: uppercase;
    letter-spacing: var(--track-rotulo);
}
.painel-secao .sub { margin: 0; font-size: var(--t-xs); }

.plano-atual-destaque {
    margin: 0; padding: var(--s-3);
    border-radius: var(--r-sm);
    background: linear-gradient(180deg, rgba(83,252,24,.12), rgba(83,252,24,.04));
    border: 1px solid rgba(83,252,24,.4);
    font-size: var(--t-xs); color: var(--fg-dim);
    display: flex; align-items: center; justify-content: space-between; gap: var(--s-2);
}
.plano-atual-destaque strong {
    color: var(--kick); font-size: var(--t-lg); font-weight: var(--w-black);
}
/* Plano grátis: vira uma linha de estado, sem verde. Duas coisas brilhando na
   mesma seção anulam uma à outra — e a que tem que ganhar é a oferta. */
.plano-atual-neutro {
    background: var(--surface-2); background-image: var(--grad-surface);
    border-color: var(--borda);
}
.plano-atual-neutro strong { color: var(--fg); font-size: var(--t-md); font-weight: var(--w-bold); }

/* Até quando o plano pago vale. Discreto no dia a dia; âmbar (a mesma cor de
   .promo-bonus e .tag-pend) na última semana, que é quando vira ação: renovar,
   ou avisar o admin de que o PIX do mês vence. */
.plano-validade { margin: var(--s-2) 0 0; font-size: var(--t-xs); color: var(--fg-dim); }
.plano-validade strong { color: var(--fg); font-weight: var(--w-bold); }
.plano-validade-alerta { color: #ffeaa3; }
.plano-validade-alerta strong { color: #ffeaa3; }

/* Card de venda do plano pago. Só aparece para quem AINDA não assina — quem já
   assina vê o estado enxuto (moedas/ciclo + "Gerenciar assinatura"), porque
   insistir na oferta com quem já comprou é ruído. */
.plano-oferta {
    border: 1px solid rgba(83,252,24,.35); border-radius: var(--r-sm);
    background: var(--surface-2); background-image: var(--grad-surface);
    padding: var(--s-4); display: flex; flex-direction: column; gap: var(--s-3);
    transition: border-color var(--dur-2) var(--ease-out),
                box-shadow var(--dur-2) var(--ease-out);
}
.plano-oferta:hover { border-color: rgba(83,252,24,.5); box-shadow: var(--glow-kick); }

.plano-oferta-topo { display: flex; justify-content: space-between; align-items: center; gap: var(--s-2); }
.plano-oferta-topo strong { font-size: var(--t-lg); font-weight: var(--w-black); }
/* A tag do card de venda já vem alinhada pelo flex do topo. */
.plano-oferta-topo .plano-tag { margin-top: 0; }

/* O gancho: o que o card promete em uma linha, antes do preço. O multiplicador
   é o número que convence — o preço vem depois, já com o valor estabelecido. */
.plano-oferta-gancho {
    margin: 0; font-size: var(--t-sm); color: var(--fg-dim);
    display: flex; align-items: baseline; gap: var(--s-2);
}
.plano-oferta-gancho strong {
    color: var(--kick); font-size: var(--t-2xl); font-weight: var(--w-black);
    line-height: 1; font-variant-numeric: tabular-nums;
}

/* Comparação Free x pago. Barra em vez de só os números: a diferença tem que
   ser vista antes de ser lida. */
.plano-barras { display: flex; flex-direction: column; gap: var(--s-2); }
.plano-barra {
    display: grid; grid-template-columns: 42px 1fr 30px; align-items: center;
    gap: var(--s-2); font-size: var(--t-2xs); color: var(--fg-mute);
    font-variant-numeric: tabular-nums;
}
.plano-barra-trilho {
    height: 6px; border-radius: 999px; background: var(--surface-4); overflow: hidden;
}
.plano-barra-preenchimento {
    display: block; height: 100%; border-radius: 999px; background: var(--fg-mute);
}
.plano-barra-valor { text-align: right; }
.plano-barra-destaque { color: var(--fg); font-weight: var(--w-bold); }
.plano-barra-destaque .plano-barra-preenchimento { background: var(--grad-kick); }

/* O preço, já ancorado pelo gancho acima. */
.plano-oferta-preco {
    margin: 0; color: var(--fg);
    font-size: var(--t-xl); font-weight: var(--w-black); line-height: 1.2;
    font-variant-numeric: tabular-nums;
}
.plano-oferta-preco span {
    color: var(--fg-dim); font-size: var(--t-xs); font-weight: var(--w-med);
}
/* Mesma quantia numa unidade que dói menos. Em linha própria, sem competir. */
.plano-oferta-dia { display: block; margin-top: 2px; font-size: var(--t-2xs); }

.plano-beneficios {
    margin: 0; padding: 0; list-style: none;
    display: flex; flex-direction: column; gap: var(--s-2);
    font-size: var(--t-xs); color: var(--fg-dim); line-height: 1.45;
}
.plano-beneficios li { padding-left: var(--s-5); position: relative; }
.plano-beneficios li::before {
    content: ""; position: absolute; left: 0; top: 2px;
    width: 14px; height: 14px; background: var(--kick);
    -webkit-mask: var(--ico-check) center/contain no-repeat;
            mask: var(--ico-check) center/contain no-repeat;
}
.plano-beneficios strong { color: var(--fg); font-weight: var(--w-semi); }

.plano-oferta-rodape { margin: 0; font-size: var(--t-2xs); color: var(--fg-mute); }

.plano-farm {
    margin-top: var(--s-1); font-size: var(--t-sm); color: var(--amarelo);
    font-weight: var(--w-bold);
    display: inline-flex; align-items: center; gap: var(--s-1);
    font-variant-numeric: tabular-nums;
}
.plano-farm::before {
    content: ""; width: 13px; height: 13px; background: var(--amarelo);
    -webkit-mask: var(--ico-moeda) center/contain no-repeat;
            mask: var(--ico-moeda) center/contain no-repeat;
}
.plano-tag {
    display: inline-block; margin-top: var(--s-2);
    padding: 2px var(--s-2); border-radius: 999px;
    background: var(--grad-kick); color: #06140a;
    font-size: var(--t-2xs); font-weight: var(--w-black);
    text-transform: uppercase; letter-spacing: .4px;
}
/* Sem margin: o único lugar onde vive é dentro de .plano-oferta, que já espaça
   por gap — somar os dois abriria um buraco antes do CTA. */
.btn-assinar { width: 100%; padding: var(--s-3); font-size: var(--t-sm); }
.btn-gerenciar { width: 100%; }

/* Cartão de ação da lateral (reservar / vitrine liberada) */
.caixa-passe {
    padding: var(--s-4); border-radius: var(--r-sm);
    border: 1px solid var(--borda); background: var(--surface-2);
    display: flex; flex-direction: column; gap: var(--s-3);
}
.caixa-passe h3 { margin: 0; font-size: var(--t-md); font-weight: var(--w-bold); }
.caixa-passe .sub { margin: 0; font-size: var(--t-xs); }
.caixa-passe label { margin: 0; }
.caixa-passe .btn-primario { padding: var(--s-3); font-size: var(--t-sm); }

.passe-msg { margin: 0; font-size: var(--t-xs); color: var(--ok); }
.passe-msg.erro { color: var(--perigo); }

/* Aviso do custo de troca de canal no modal "Meu canal". */
.aviso-custo {
    margin: 0 0 12px; padding: 8px 10px; font-size: 12px; line-height: 1.4;
    border-radius: var(--r-sm); border: 1px solid rgba(247,214,78,.35);
    background: rgba(247,214,78,.1); color: var(--amarelo);
}

/* ---------- Fila de reservas: uma linha por hora fechada ---------- */
.reserva-horarios { display: flex; flex-direction: column; gap: var(--s-2); }
.reserva-hora {
    display: flex; align-items: center; gap: var(--s-2);
    padding: var(--s-2) var(--s-3); border-radius: var(--r-xs);
    border: 1px solid var(--borda); background: var(--surface-1);
}
.reserva-hora-label {
    font-weight: var(--w-bold); font-size: var(--t-sm);
    font-variant-numeric: tabular-nums;
}
.reserva-hora-estado {
    margin-left: auto; font-size: var(--t-2xs); font-weight: var(--w-bold);
    text-transform: uppercase; letter-spacing: .4px;
}
.reserva-hora-estado.estado-pendente   { color: var(--aviso); }
.reserva-hora-estado.estado-confirmada { color: var(--ok); }
.reserva-hora .btn-mini { margin-left: auto; }
.reserva-hora .btn-mini + .btn-mini,
.reserva-hora-estado + .btn-mini { margin-left: var(--s-2); }
/* Quantos já disputam esta hora (fica colado no horário, não empurra o botão). */
.reserva-hora-ocupacao {
    font-size: var(--t-2xs); font-weight: var(--w-bold); color: var(--fg-dim);
    font-variant-numeric: tabular-nums;
    padding: 2px var(--s-2); border-radius: 999px;
    border: 1px solid var(--borda); background: var(--surface-2);
}
/* Hora cheia no total, mas o plano do usuário fura a fila */
.reserva-hora-ocupacao.ocupacao-prioridade {
    color: var(--ok); border-color: rgba(61,255,106,.35);
    background: rgba(61,255,106,.08);
}

/* Fila cheia: nenhuma hora do horizonte tem vaga */
.reserva-cheia {
    margin: 0; padding: var(--s-3); border-radius: var(--r-xs);
    border: 1px solid rgba(247,214,78,.35); background: rgba(247,214,78,.08);
    color: var(--fg-dim); font-size: var(--t-xs); line-height: 1.5;
}
.reserva-cheia strong { color: var(--amarelo); }

/* Vaga comprometida por um plano superior: pede uma decisão ao usuário */
.alerta-vaga {
    padding: var(--s-4); border-radius: var(--r-sm);
    border: 1px solid rgba(255,93,93,.4); background: rgba(255,93,93,.08);
    display: flex; flex-direction: column; gap: var(--s-2);
}
.alerta-vaga h3 {
    margin: 0; display: flex; align-items: center; gap: var(--s-2);
    font-size: var(--t-md); font-weight: var(--w-bold); color: #ff8b8b;
}
.alerta-vaga h3 .ico {
    -webkit-mask-image: var(--ico-alerta); mask-image: var(--ico-alerta);
}
.alerta-vaga-texto { margin: 0; font-size: var(--t-sm); line-height: 1.5; color: var(--fg); }
.alerta-vaga-acoes { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.alerta-vaga-acoes .btn-mini { width: auto; }
.alerta-vaga-nota { font-size: var(--t-xs); line-height: 1.5; margin: 0; }

/* Contador "usuários farmando agora" (admin/VIP) */
.farmando-info strong { color: var(--ok); font-variant-numeric: tabular-nums; }

/* Switch "estou ao vivo" (admin/VIP) */
.switch-linha {
    display: flex; align-items: center; gap: var(--s-3);
    margin: 0; cursor: pointer; user-select: none;
    font-size: var(--t-sm); font-weight: var(--w-semi); color: var(--fg);
}
/* O texto acompanha o switch: verde só quando está de fato no ar. */
.switch-linha:has(.switch:checked) { color: var(--ok); }
.switch {
    appearance: none; -webkit-appearance: none;
    flex: none; width: 42px; height: 24px; border-radius: 999px;
    border: 1px solid var(--borda); background: var(--surface-3);
    position: relative; cursor: pointer;
    transition: background var(--dur-2) var(--ease-out),
                border-color var(--dur-2) var(--ease-out);
}
.switch::after {
    content: ""; position: absolute; top: 2px; left: 2px;
    width: 18px; height: 18px; border-radius: 50%;
    background: var(--fg-dim);
    transition: transform var(--dur-2) var(--ease-out),
                background var(--dur-2) var(--ease-out);
}
.switch:checked { background: rgba(61,255,106,.18); border-color: rgba(61,255,106,.45); }
.switch:checked::after { transform: translateX(18px); background: var(--ok); }
.switch:disabled { opacity: .5; cursor: progress; }
.switch:focus-visible { outline: 2px solid var(--ok); outline-offset: 2px; }

/* =========================================================
   Modal "meu canal"
   ========================================================= */
#modal-config, #modal-indicacao {
    border: 1px solid var(--borda); border-radius: var(--r);
    background: var(--surface-2); background-image: var(--grad-surface);
    color: var(--fg); width: min(440px, 92vw); padding: var(--s-6);
    box-shadow: var(--sh-3);
}
#modal-config::backdrop, #modal-indicacao::backdrop { background: rgba(4,4,8,.66); backdrop-filter: blur(3px); }
/* A lista de indicados pode crescer: rola dentro do modal em vez de esticar
   além da tela (o launcher roda em janelas pequenas). */
#modal-indicacao { width: min(520px, 92vw); max-height: 86vh; overflow-y: auto; }
.form-config h2 { margin: 0 0 var(--s-1); font-size: var(--t-xl); font-weight: var(--w-black); }
.form-config .sub { margin-bottom: var(--s-5); }
.acoes-modal { display: flex; gap: var(--s-3); margin-top: var(--s-4); }
.acoes-modal .btn-primario, .acoes-modal .btn-sec { width: auto; flex: 1; }

/* Link de convite: código e link são readonly, mas continuam selecionáveis —
   o botão "copiar" pode falhar e a seleção à mão é o plano B. */
#modal-indicacao input[readonly] {
    cursor: text; color: var(--fg-dim);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--t-xs);
}
.indicacao-titulo {
    margin: var(--s-6) 0 var(--s-2); font-size: var(--t-sm); font-weight: var(--w-black);
    text-transform: uppercase; letter-spacing: .4px; color: var(--fg-dim);
}
.lista-indicados { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-2); }
.indicado {
    display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
    padding: var(--s-2) var(--s-3); border: 1px solid var(--borda); border-radius: var(--r-sm);
    background: rgba(255,255,255,.03);
}
.indicado-nome { font-weight: var(--w-bold); overflow-wrap: anywhere; }
.indicado-estado { font-size: var(--t-xs); color: var(--fg-dim); white-space: nowrap; }
/* Quem já fechou o ciclo é quem de fato pagou o bônus: destaque discreto. */
.indicado-ok { border-color: rgba(83,252,24,.35); background: rgba(83,252,24,.06); }
.indicado-ok .indicado-estado { color: var(--kick); }

/* Campo opcional no cadastro */
.rotulo-opcional { font-weight: var(--w-reg); color: var(--fg-mute); font-size: var(--t-xs); }
.campo-nota { margin: calc(var(--s-2) * -1) 0 var(--s-4); font-size: var(--t-xs); }

/* Aviso fixo fora do launcher */
.fora-do-app {
    position: fixed; left: 50%; bottom: var(--s-4); transform: translateX(-50%);
    background: var(--surface-3); border: 1px solid var(--borda); color: var(--fg-dim);
    padding: var(--s-3) var(--s-5); border-radius: 999px;
    font-size: var(--t-sm); box-shadow: var(--sh-2);
}

/* =========================================================
   Admin
   ========================================================= */
.tela-admin { min-height: 100vh; display: flex; flex-direction: column; }
.admin-corpo { padding: var(--s-5); overflow: auto; }

/* Controle global do admin (DoubleCoins). */
.bloco-global {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--s-4); flex-wrap: wrap;
    margin-bottom: var(--s-6); padding: var(--s-4);
    background: var(--surface-2); border: 1px solid var(--borda); border-radius: 10px;
}
.bloco-global.double-on {
    border-color: rgba(255,216,74,.6);
    background: linear-gradient(180deg, rgba(255,216,74,.10), rgba(255,216,74,.03));
}
.bloco-global h2 { font-size: var(--t-lg); font-weight: var(--w-black); margin: 0 0 var(--s-2); }
.bloco-global .sub { margin: 0; max-width: 62ch; }
.global-estado {
    margin-left: var(--s-2); padding: 2px var(--s-2); border-radius: 999px;
    font-size: var(--t-xs); font-weight: var(--w-black);
    background: rgba(255,255,255,.08); color: var(--fg-dim);
}
.bloco-global.double-on .global-estado { background: var(--amarelo); color: #1a1400; }
.btn-double {
    padding: var(--s-3) var(--s-4); font-weight: var(--w-black); white-space: nowrap; cursor: pointer;
    background: var(--surface-3); color: var(--fg);
    border: 1px solid var(--borda-forte); border-radius: 8px;
}
.btn-double:hover { background: var(--surface-4); }
.btn-double-on { background: var(--amarelo); border-color: transparent; color: #1a1400; }
.btn-double-on:hover { filter: brightness(1.06); background: var(--amarelo); }

.bloco-pendentes { margin-bottom: var(--s-6); }
.bloco-pendentes h2 {
    font-size: var(--t-lg); font-weight: var(--w-black); margin: 0 0 var(--s-3);
    display: flex; align-items: center; gap: var(--s-2);
}
.contador-pend {
    background: var(--amarelo); color: #1a1400;
    font-size: var(--t-xs); font-weight: var(--w-black);
    border-radius: 999px; padding: 2px var(--s-2); min-width: 22px; text-align: center;
    font-variant-numeric: tabular-nums;
}

.tabela-admin {
    width: 100%; border-collapse: separate; border-spacing: 0;
    font-size: var(--t-sm);
    background: var(--surface-1); border: 1px solid var(--borda); border-radius: var(--r-sm);
    overflow: hidden;
}
.tabela-admin th, .tabela-admin td {
    padding: var(--s-3); border-bottom: 1px solid var(--borda);
    text-align: left; vertical-align: middle;
}
/* Quebra da frota por versão do launcher (admin/saude.php). A barra existe para
   dar a proporção de relance: com 60 instalações, "8" e "41" no meio de uma
   coluna de números não contam a mesma história que duas barras lado a lado. */
.tabela-versoes { max-width: 520px; margin-bottom: var(--s-4); }
.barra-versao-celula { width: 55%; white-space: nowrap; }
.barra-versao {
    display: inline-block; height: 8px; min-width: 2px; margin-right: var(--s-2);
    vertical-align: middle; border-radius: 4px;
    background: var(--borda-forte);
}
/* Só a versão publicada fica verde: o resto é o que ainda falta migrar. */
.barra-versao-ok { background: var(--verde); }

/* Rolar 100 usuários perdia os cabeçalhos: eles ficam. */
.tabela-admin thead th {
    position: sticky; top: 0; z-index: 2;
    color: var(--fg-mute); font-size: var(--t-2xs);
    text-transform: uppercase; letter-spacing: var(--track-rotulo);
    font-weight: var(--w-bold); background: var(--surface-3);
    box-shadow: inset 0 -1px 0 var(--borda);
}
.tabela-admin tbody tr:last-child td { border-bottom: 0; }
.tabela-admin tbody tr:hover { background: rgba(255,255,255,.02); }
.tabela-admin td.num {
    text-align: right; color: var(--amarelo);
    font-weight: var(--w-bold); font-variant-numeric: tabular-nums;
}

/* Stack trace vindo do launcher (admin/saude.php). Rola no eixo X em vez de
   esticar a tabela: linha de exceção .NET é longa e empurraria as colunas. */
.crash-log {
    margin: var(--s-2) 0 0;
    padding: var(--s-3);
    background: var(--surface-3); border: 1px solid var(--borda); border-radius: var(--r-sm);
    color: var(--fg-dim); font-size: var(--t-2xs); line-height: 1.5;
    font-family: ui-monospace, Consolas, monospace;
    max-height: 220px; overflow: auto; white-space: pre;
}
.tabela-admin small.sub { display: block; margin: 3px 0 0; color: var(--fg-mute); font-size: var(--t-xs); }

.form-linha { display: flex; gap: var(--s-1); align-items: center; }
.form-linha + .form-linha { margin-top: var(--s-1); }
.form-linha select, .form-linha input {
    padding: var(--s-1) var(--s-2); background: var(--surface-3);
    border: 1px solid var(--borda); border-radius: var(--r-xs);
    color: var(--fg); font-family: inherit; font-size: var(--t-xs);
    min-height: 30px;
}
.form-linha input[type="number"] { width: 72px; }
.form-linha input[type="text"] { width: 118px; }
.form-linha select { min-width: 92px; }
.form-linha select:focus, .form-linha input:focus {
    outline: none; border-color: var(--kick); box-shadow: var(--glow-kick-soft);
}

.btn-mini {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 32px; padding: var(--s-1) var(--s-3);
    border-radius: var(--r-xs); border: 1px solid var(--borda);
    background: var(--surface-3); color: var(--fg);
    font-family: inherit; font-size: var(--t-xs); font-weight: var(--w-semi);
    cursor: pointer; white-space: nowrap;
    transition: border-color var(--dur-2) var(--ease-out),
                background var(--dur-2) var(--ease-out);
}
.btn-mini:hover { border-color: var(--borda-forte); background: var(--surface-4); }
/* Estado ligado / ação positiva → verde do tema */
.btn-mini-on { background: var(--grad-kick); border-color: transparent; color: #06140a; }
.btn-mini-on:hover { filter: brightness(1.06); background: var(--grad-kick); }
/* Ação de cautela (bloquear) → âmbar */
.btn-mini-warn {
    background: rgba(247,214,78,.14); border-color: rgba(247,214,78,.5); color: var(--amarelo);
}
.btn-mini-warn:hover { background: rgba(247,214,78,.22); border-color: var(--amarelo); }
/* Ação destrutiva (remover) → vermelho */
.btn-mini-danger {
    background: rgba(255,80,96,.12); border-color: rgba(255,80,96,.5); color: #ff8b95;
}
.btn-mini-danger:hover { background: rgba(255,80,96,.2); border-color: var(--perigo); color: #ffb3ba; }
/* Botão primário em tamanho de linha (fila de reservas) */
.btn-primario.btn-mini { width: auto; padding: var(--s-1) var(--s-3); font-size: var(--t-xs); }
.btn-sec.btn-mini {
    min-height: 32px; padding: var(--s-1) var(--s-3);
    font-size: var(--t-xs); font-weight: var(--w-semi);
}

/* Coluna de ações: botões empilhados, alinhados e com respiro.
   O destrutivo não fica encostado no resto — cor não basta para separar risco. */
.acoes-admin { display: flex; flex-direction: column; gap: var(--s-1); align-items: stretch; }
.acoes-admin form { display: flex; }
.acoes-admin .btn-mini { width: 100%; }
.acoes-admin .acao-perigo {
    margin-top: var(--s-2); padding-top: var(--s-2);
    border-top: 1px solid var(--borda);
}

/* Tags de status e cargo */
.tag-vivo {
    margin-left: 5px; padding: 2px var(--s-2); border-radius: 999px;
    background: var(--perigo); color: #fff;
    font-size: var(--t-2xs); font-weight: var(--w-bold);
}
.tag-status {
    display: inline-block; padding: 2px var(--s-2); border-radius: 999px;
    font-size: var(--t-2xs); font-weight: var(--w-black);
    text-transform: uppercase; letter-spacing: .3px;
}
.tag-ok    { background: rgba(61,255,106,.15); color: var(--ok); }
.tag-pend  { background: rgba(247,214,78,.18); color: var(--aviso); }
.tag-off   { background: rgba(255,80,96,.15); color: var(--perigo); }
/* Informativa, sem juízo de valor: marca a origem de uma assinatura do Stripe,
   que não é boa nem ruim — só diferente da concedida na mão. */
.tag-neutro { background: var(--surface-2); color: var(--fg-dim); }

.tag-role {
    display: inline-block; margin-left: 5px;
    padding: 1px var(--s-2); border-radius: 999px;
    font-size: var(--t-2xs); font-weight: var(--w-black);
    text-transform: uppercase; letter-spacing: .3px;
    vertical-align: middle;
}
.tag-admin { background: var(--grad-kick); color: #06140a; }
.tag-vip   { background: linear-gradient(180deg, #ffd85a, #f2b705); color: #241a00; }
.tag-passe { background: rgba(83,252,24,.13); color: var(--kick); }

/* ---------- Grade & reservas (admin/grade.php) ---------- */
.bloco-hora { margin-bottom: var(--s-6); }
/* Cabeçalho de bloco: a HORA manda; ocupação e tags são subordinadas. */
.bloco-hora h2 {
    font-size: var(--t-xl); font-weight: var(--w-black); margin: 0 0 var(--s-2);
    display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
    font-variant-numeric: tabular-nums; letter-spacing: -.2px;
}
.bloco-hora .sub { margin: 0 0 var(--s-3); font-size: var(--t-sm); max-width: 860px; }
.sub-hora {
    color: var(--fg-mute); font-size: var(--t-xs); font-weight: var(--w-reg);
    letter-spacing: 0;
}
.ocupacao {
    background: var(--surface-3); border: 1px solid var(--borda); color: var(--fg-dim);
    font-size: var(--t-xs); font-weight: var(--w-bold);
    border-radius: 999px; padding: 2px var(--s-3);
    font-variant-numeric: tabular-nums; letter-spacing: 0;
}
.ocupacao-cheia { background: rgba(255,80,96,.14); border-color: rgba(255,80,96,.5); color: #ff8b95; }

.tag-tier {
    display: inline-block; padding: 2px var(--s-2); border-radius: 999px;
    font-size: var(--t-2xs); font-weight: var(--w-black);
    text-transform: uppercase; letter-spacing: .3px;
}
.tag-tier-cuiudo { background: rgba(83,252,24,.15); color: var(--kick); }
.tag-tier-gold   { background: rgba(247,214,78,.18); color: var(--amarelo); }
.tag-tier-free   { background: rgba(255,255,255,.07); color: var(--fg-dim); }

/* Reserva além da capacidade: vai perder a vaga na virada.
   O fundo a 5% era invisível — agora a linha ganha uma marca na lateral. */
.linha-risco td { background: rgba(255,80,96,.1); }
.linha-risco td:first-child { box-shadow: inset 3px 0 0 var(--perigo); }

/* Ranking: realce leve do pódio (top 3 do tempo assistido). */
.linha-topo td { background: rgba(83,252,24,.06); }
.linha-topo td:first-child { box-shadow: inset 3px 0 0 var(--kick); color: var(--kick); font-weight: 800; }

.check-estorno {
    display: flex; align-items: center; gap: var(--s-1);
    font-size: var(--t-xs); color: var(--fg-dim); white-space: nowrap; cursor: pointer;
}
.check-estorno input { width: auto; margin: 0; }

/* =========================================================
   Portão app-vs-navegador na tela de entrada. O <script> no index.php marca
   html.em-app (dentro do launcher) ou html.no-app (navegador comum).
   ========================================================= */
.so-no-app        { display: none; }
html.em-app .so-no-app { display: block; }
.aviso-abrir-app  { display: none; }
html.no-app .aviso-abrir-app { display: block; }
/* Site público (config site.aberto): o navegador comum também entra e cadastra. */
html.site-aberto .so-no-app { display: block; }
html.site-aberto .aviso-abrir-app { display: none; }
html.site-aberto .marca-mark { background-image: url('v2/logo.png'); }
html.site-aberto .card-auth .voltar-site { display: block; text-align: center; margin-top: 14px; }
.voltar-site { display: none; }
.texto-abrir-app {
    color: var(--fg-dim); font-size: var(--t-md); line-height: 1.6;
    margin: var(--s-3) 0 0;
}

/* Respeita quem prefere menos animação */
@media (prefers-reduced-motion: reduce) {
    * { animation-duration: .001ms !important; animation-iteration-count: 1 !important;
        transition-duration: .001ms !important; }
}
