/* =============================================================
   Stars Admin — UI
   Tema claro/escuro por tokens. Sem escolha manual segue o
   sistema (prefers-color-scheme); a alternancia grava em
   localStorage e vira data-theme no <html> (ver admin.js).
   Regra: componente NUNCA usa cor literal — so var(--token).
   ============================================================= */

/* ---------- Tokens: claro (padrao) ---------- */
:root {
    color-scheme: light;

    --bg: #f4f6fa;
    --bg-elev: #ffffff;
    --surface: #ffffff;
    --surface-2: #f2f4f9;
    --surface-3: #e9edf5;
    --border: #e3e7f0;
    --border-strong: #cfd6e4;

    --text: #131722;
    --muted: #5b6577;
    --faint: #8b94a6;

    /* vermelho da marca (logo = #fe000d), escurecido o bastante para
       texto branco passar em contraste sobre o preenchimento */
    --accent: #c8121d;
    --accent-hi: #e5202c;
    --accent-ink: #ffffff;
    --accent-fg: #c0111c;
    --accent-soft: rgba(226, 26, 40, .12);
    --accent-line: rgba(200, 18, 29, .38);

    --green: #12874a;
    /* vermelho de VALOR (saida/negativo): mais escuro que o --accent de acao
       de proposito, para nao confundir numero com botao */
    --red: #9c1a14;
    --gold: #92650a;
    /* lilas da plataforma — contraste 7,1:1 no card claro (medido) */
    --plat: #6d28d9;
    --plat-soft: rgba(109, 40, 217, .10);
    --plat-line: rgba(109, 40, 217, .32);
    /* Cores ESCOLHIVEIS do badge da plataforma (sql/047, Plataformas::CORES).
       Texto >= 4,5:1 SOBRE O FUNDO TINGIDO do badge (nao so sobre o card —
       medido com a tinta de 10% por cima): azul 5,7 · rosa 5,1 · laranja 5,3
       · verde 5,1 · amarelo 5,2. Laranja/verde/amarelo sao um passo mais
       escuros que o natural por isso. Distancias: validate_palette.js.
       Os pares que se confundem estao em Plataformas::CORES_PARECIDAS. */
    --pc-azul: #1d4ed8;    --pc-azul-soft: rgba(29, 78, 216, .10);    --pc-azul-line: rgba(29, 78, 216, .32);
    --pc-rosa: #be185d;    --pc-rosa-soft: rgba(190, 24, 93, .10);    --pc-rosa-line: rgba(190, 24, 93, .32);
    --pc-laranja: #ad3a0b; --pc-laranja-soft: rgba(173, 58, 11, .10); --pc-laranja-line: rgba(173, 58, 11, .32);
    --pc-verde: #13733a;   --pc-verde-soft: rgba(19, 115, 58, .10);   --pc-verde-line: rgba(19, 115, 58, .32);
    --pc-amarelo: #8c5706; --pc-amarelo-soft: rgba(140, 87, 6, .10);  --pc-amarelo-line: rgba(140, 87, 6, .32);
    /* ciano do atendente — 5,4:1 no claro (medido) */
    --atend: #0e7490;
    --atend-soft: rgba(14, 116, 144, .10);
    --atend-line: rgba(14, 116, 144, .32);

    /* Series do grafico — validadas com scripts/validate_palette.js:
       claro PASS (deutan ΔE 9.6). Mesmo assim a cor nunca anda sozinha:
       o traco de saque e tracejado e a legenda traz o total. */
    --chart-in: #12874a;
    --chart-out: #9c1a14;
    /* neutro do "resto" em barra de contagem (cadastros x quem converteu).
       Validado sobre o branco do card: contraste 3,1:1, ΔE 10,6 (deutan) e
       16,5 (visao normal) contra o --chart-in. Cinza de proposito: nao e uma
       terceira serie, e a parte que ainda nao virou nada. */
    --chart-neutral: #78829a;

    /* Motivos da fila de saque (codigos *001*..*005* da descricao) — 5 cores
       categoricas validadas com o validate_palette.js da skill dataviz sobre
       o branco (adjacentes: pior deutan ΔE 13,0; visao normal 25,7; todas
       >= 3:1). A cor nunca anda sozinha: a bolinha carrega o DIGITO do
       codigo e a legenda em cima traz o rotulo por extenso. */
    --motivo-001: #1d4ed8;   /* acima do limite por saque */
    --motivo-002: #d97706;   /* limite diario geral */
    --motivo-003: #8b5cf6;   /* sem premios suficientes */
    --motivo-004: #be185d;   /* erro na API do gateway */
    --motivo-005: #0891b2;   /* primeiro saque */

    --ok-bg: #e8f6ed;
    --ok-border: #a9dcbe;
    --ok-text: #10693c;
    --err-bg: #fdecec;
    --err-border: #f3bcbc;
    --err-text: #a11d1d;

    --row-hover: rgba(19, 23, 34, .035);
    --scrim: rgba(14, 18, 28, .45);

    --shadow-1: 0 1px 2px rgba(16, 24, 40, .05), 0 1px 3px rgba(16, 24, 40, .07);
    --shadow-2: 0 10px 30px rgba(16, 24, 40, .12);
    --shadow-3: 0 24px 60px rgba(16, 24, 40, .18);

    /* Capa de reserva do jogo de cassino sem imagem (fundo + 🎰, 05/11/2026).
       E ARTE, nao dado: as mesmas seis cores nos dois temas, com uma luz no
       alto para a capa nao sair chapada. */
    --capa-luz: radial-gradient(circle at 30% 16%, rgba(255, 255, 255, .32), transparent 60%);
    --capa-1: linear-gradient(160deg, #8b5cf6, #4c1d95);
    --capa-2: linear-gradient(160deg, #3b82f6, #1e3a8a);
    --capa-3: linear-gradient(160deg, #10b981, #065f46);
    --capa-4: linear-gradient(160deg, #ec4899, #831843);
    --capa-5: linear-gradient(160deg, #f59e0b, #9a3412);
    --capa-6: linear-gradient(160deg, #06b6d4, #155e75);
    --capa-sombra: rgba(0, 0, 0, .4);

    --radius: 12px;
    --radius-sm: 8px;
    --radius-lg: 16px;
    --sidebar-w: 244px;
    --topbar-h: 56px;
}

/* ---------- Tokens: escuro ---------- */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        color-scheme: dark;

        --bg: #0b0e14;
        --bg-elev: #10141d;
        --surface: #141926;
        --surface-2: #1b2130;
        --surface-3: #222a3a;
        --border: #272f40;
        --border-strong: #3a4459;

        --text: #e9edf6;
        --muted: #97a1b6;
        --faint: #6d778c;

        --accent: #c8121d;
        --accent-hi: #e5202c;
        --accent-ink: #ffffff;
        --accent-fg: #ff7a84;
        --accent-soft: rgba(255, 60, 72, .14);
        --accent-line: rgba(255, 70, 82, .42);

        --green: #3ecf72;
        --red: #ff9a9a;
        --gold: #f5b301;
        /* lilas da plataforma — 9,5:1 no card escuro (medido) */
        --plat: #c4b5fd;
        --plat-soft: rgba(167, 139, 250, .13);
        --plat-line: rgba(167, 139, 250, .34);
        /* badge escolhivel no escuro: tons 400 (os 300, pastel, se confundiam
           entre si e o azul com o ciano do atendente). Texto 6,6 a 11,5:1. */
        --pc-azul: #60a5fa;    --pc-azul-soft: rgba(96, 165, 250, .14);    --pc-azul-line: rgba(96, 165, 250, .36);
        --pc-rosa: #f472b6;    --pc-rosa-soft: rgba(244, 114, 182, .14);   --pc-rosa-line: rgba(244, 114, 182, .36);
        --pc-laranja: #fb923c; --pc-laranja-soft: rgba(251, 146, 60, .14); --pc-laranja-line: rgba(251, 146, 60, .36);
        --pc-verde: #4ade80;   --pc-verde-soft: rgba(74, 222, 128, .14);   --pc-verde-line: rgba(74, 222, 128, .36);
        --pc-amarelo: #facc15; --pc-amarelo-soft: rgba(250, 204, 21, .14); --pc-amarelo-line: rgba(250, 204, 21, .36);
        /* ciano do atendente — 12,1:1 no escuro; separa bem do verde de
           status, que fica na coluna do lado (medido) */
        --atend: #67e8f9;
        --atend-soft: rgba(103, 232, 249, .12);
        --atend-line: rgba(103, 232, 249, .32);

        /* Serie do grafico no escuro: passos proprios (nao e flip do claro).
           Validado: deutan ΔE 7.7 = banda de piso, legal SO com o canal
           extra que ja existe (traco tracejado + total na legenda). */
        --chart-in: #17a06a;
        --chart-out: #ee5a52;
        /* passo proprio do escuro: 3,4:1 sobre o card, ΔE 9,5 (deutan) e
           16,0 (visao normal) contra o --chart-in */
        --chart-neutral: #6d778c;

        /* Motivos da fila de saque: passos proprios do escuro (nao e flip do
           claro) — validados sobre #141926 (adjacentes: pior deutan ΔE 10,3;
           visao normal 26,4; todas >= 3:1). */
        --motivo-001: #3b82f6;
        --motivo-002: #d97706;
        --motivo-003: #7c3aed;
        --motivo-004: #db2777;
        --motivo-005: #0891b2;

        --ok-bg: #12301f;
        --ok-border: #2c6a41;
        --ok-text: #7fe3a5;
        --err-bg: #351b20;
        --err-border: #6e2a34;
        --err-text: #ff9aa2;

        --row-hover: rgba(255, 255, 255, .028);
        --scrim: rgba(3, 5, 10, .62);

        --shadow-1: 0 1px 2px rgba(0, 0, 0, .35);
        --shadow-2: 0 12px 32px rgba(0, 0, 0, .45);
        --shadow-3: 0 28px 70px rgba(0, 0, 0, .6);

        /* Capa de reserva do jogo de cassino sem imagem (fundo + 🎰, 05/11/2026).
           E ARTE, nao dado: as mesmas seis cores nos dois temas, com uma luz no
           alto para a capa nao sair chapada. */
        --capa-luz: radial-gradient(circle at 30% 16%, rgba(255, 255, 255, .32), transparent 60%);
        --capa-1: linear-gradient(160deg, #8b5cf6, #4c1d95);
        --capa-2: linear-gradient(160deg, #3b82f6, #1e3a8a);
        --capa-3: linear-gradient(160deg, #10b981, #065f46);
        --capa-4: linear-gradient(160deg, #ec4899, #831843);
        --capa-5: linear-gradient(160deg, #f59e0b, #9a3412);
        --capa-6: linear-gradient(160deg, #06b6d4, #155e75);
        --capa-sombra: rgba(0, 0, 0, .4);
    }
}

:root[data-theme="dark"] {
    color-scheme: dark;

    --bg: #0b0e14;
    --bg-elev: #10141d;
    --surface: #141926;
    --surface-2: #1b2130;
    --surface-3: #222a3a;
    --border: #272f40;
    --border-strong: #3a4459;

    --text: #e9edf6;
    --muted: #97a1b6;
    --faint: #6d778c;

    --accent: #c8121d;
    --accent-hi: #e5202c;
    --accent-ink: #ffffff;
    --accent-fg: #ff7a84;
    --accent-soft: rgba(255, 60, 72, .14);
    --accent-line: rgba(255, 70, 82, .42);

    --green: #3ecf72;
    --red: #ff9a9a;
    --gold: #f5b301;
    /* lilas da plataforma — 9,5:1 no card escuro (medido) */
    --plat: #c4b5fd;
    --plat-soft: rgba(167, 139, 250, .13);
    --plat-line: rgba(167, 139, 250, .34);
    /* mesmos tons do bloco escuro acima (o do botao de tema tem de bater) */
    --pc-azul: #60a5fa;    --pc-azul-soft: rgba(96, 165, 250, .14);    --pc-azul-line: rgba(96, 165, 250, .36);
    --pc-rosa: #f472b6;    --pc-rosa-soft: rgba(244, 114, 182, .14);   --pc-rosa-line: rgba(244, 114, 182, .36);
    --pc-laranja: #fb923c; --pc-laranja-soft: rgba(251, 146, 60, .14); --pc-laranja-line: rgba(251, 146, 60, .36);
    --pc-verde: #4ade80;   --pc-verde-soft: rgba(74, 222, 128, .14);   --pc-verde-line: rgba(74, 222, 128, .36);
    --pc-amarelo: #facc15; --pc-amarelo-soft: rgba(250, 204, 21, .14); --pc-amarelo-line: rgba(250, 204, 21, .36);
    /* ciano do atendente — 12,1:1 no escuro; separa bem do verde de
       status, que fica na coluna do lado (medido) */
    --atend: #67e8f9;
    --atend-soft: rgba(103, 232, 249, .12);
    --atend-line: rgba(103, 232, 249, .32);

    /* Serie do grafico no escuro: passos proprios (nao e flip do claro).
       Validado: deutan ΔE 7.7 = banda de piso, legal SO com o canal
       extra que ja existe (traco tracejado + total na legenda). */
    --chart-in: #17a06a;
    --chart-out: #ee5a52;
    /* passo proprio do escuro: 3,4:1 sobre o card, ΔE 9,5 (deutan) e
       16,0 (visao normal) contra o --chart-in */
    --chart-neutral: #6d778c;

    /* Motivos da fila de saque — mesmos passos do bloco escuro acima */
    --motivo-001: #3b82f6;
    --motivo-002: #d97706;
    --motivo-003: #7c3aed;
    --motivo-004: #db2777;
    --motivo-005: #0891b2;

    --ok-bg: #12301f;
    --ok-border: #2c6a41;
    --ok-text: #7fe3a5;
    --err-bg: #351b20;
    --err-border: #6e2a34;
    --err-text: #ff9aa2;

    --row-hover: rgba(255, 255, 255, .028);
    --scrim: rgba(3, 5, 10, .62);

    --shadow-1: 0 1px 2px rgba(0, 0, 0, .35);
    --shadow-2: 0 12px 32px rgba(0, 0, 0, .45);
    --shadow-3: 0 28px 70px rgba(0, 0, 0, .6);

    /* capa de reserva: as mesmas cores do claro (e arte, nao dado) */
    --capa-luz: radial-gradient(circle at 30% 16%, rgba(255, 255, 255, .32), transparent 60%);
    --capa-1: linear-gradient(160deg, #8b5cf6, #4c1d95);
    --capa-2: linear-gradient(160deg, #3b82f6, #1e3a8a);
    --capa-3: linear-gradient(160deg, #10b981, #065f46);
    --capa-4: linear-gradient(160deg, #ec4899, #831843);
    --capa-5: linear-gradient(160deg, #f59e0b, #9a3412);
    --capa-6: linear-gradient(160deg, #06b6d4, #155e75);
    --capa-sombra: rgba(0, 0, 0, .4);
}

/* ================= BASE ================= */
* { box-sizing: border-box; }

/* `hidden` sempre esconde, ponto. O `display: none` que o navegador da ao
   atributo vem da folha de UA, entao QUALQUER `display:` numa classe do painel
   vence e o elemento aparece — e o JS que faz `el.hidden = true` fica mudo.
   Ja mordeu tres vezes (`.atalho-salvar`, `.modal-backdrop` e o veu de
   carregando, que em 10/09 ficou visivel em toda pagina). Esta linha fecha a
   classe inteira do problema; as reposicoes pontuais espalhadas pelo arquivo
   ficaram onde estao, sao inofensivas. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    font-size: 15px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { margin: 0 0 .5rem; font-weight: 650; letter-spacing: -.01em; }
a { color: var(--accent-fg); text-decoration-thickness: 1px; text-underline-offset: 2px; }
p { margin: 0 0 .8rem; }

.muted { color: var(--muted); }
.small { font-size: .82rem; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .85em; }
/* .gold = bonus no dashboard; ficou como cor de DADO (a de marca virou o
   vermelho da logo), por isso token proprio e nao --accent-fg */
.gold { color: var(--gold); }
.green { color: var(--green); }
.red { color: var(--red); }
code {
    background: var(--surface-2);
    border: 1px solid var(--border);
    padding: .08em .38em;
    border-radius: 5px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .85em;
}

/* ---- Logo ----
   O wordmark tem duas artes (letras claras/escuras). Em vez de filtro CSS,
   as duas vao no HTML e o tema mostra a certa — mesmo mecanismo do sol/lua. */
.theme-light-only { display: block; }
.theme-dark-only { display: none; }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .theme-light-only { display: none; }
    :root:not([data-theme="light"]) .theme-dark-only { display: block; }
}
:root[data-theme="dark"] .theme-light-only { display: none; }
:root[data-theme="dark"] .theme-dark-only { display: block; }
:root[data-theme="light"] .theme-light-only { display: block; }
:root[data-theme="light"] .theme-dark-only { display: none; }

.brand-mark { width: 26px; height: 26px; flex-shrink: 0; display: block; }
.brand-logo { display: block; height: auto; }

.sr-only {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.skip-link {
    position: absolute; left: .6rem; top: -3rem; z-index: 100;
    background: var(--surface); color: var(--text);
    border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
    padding: .5rem .9rem; font-weight: 600; text-decoration: none;
    transition: top .15s;
}
.skip-link:focus { top: .6rem; }

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 4px;
}

/* ---- Botoes ---- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .4rem;
    min-height: 40px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    padding: .5rem 1rem;
    font: inherit;
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
    transition: background .14s, border-color .14s, color .14s, box-shadow .14s, transform .06s;
}
.btn:active { transform: translateY(1px); }

.btn-primary {
    background: linear-gradient(180deg, var(--accent-hi), var(--accent));
    color: var(--accent-ink);
    box-shadow: 0 1px 2px rgba(0, 0, 0, .12), 0 4px 14px var(--accent-soft);
}
.btn-primary:hover { filter: brightness(1.05); }

.btn-ghost {
    background: var(--bg-elev);
    color: var(--text);
    border-color: var(--border-strong);
    font-weight: 550;
    box-shadow: var(--shadow-1);
}
.btn-ghost:hover {
    background: var(--surface-3);
    border-color: var(--muted);
}
.btn svg { flex-shrink: 0; opacity: .7; }
.btn:hover svg { opacity: 1; }

/* acao destrutiva: contorno, nao preenchimento — o preenchido e o primario */
.btn-danger {
    background: var(--err-bg);
    color: var(--err-text);
    border-color: var(--err-border);
}
.btn-danger:hover { filter: brightness(.96); }

.btn-lg { width: 100%; min-height: 48px; padding: .8rem 1rem; font-size: 1.02rem; }
.btn-sm { min-height: 34px; padding: .3rem .75rem; font-size: .84rem; font-weight: 550; }

/* Botao so-icone (menu, tema, fechar) */
.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px; height: 40px;
    flex-shrink: 0;
    padding: 0;
    background: transparent;
    color: var(--muted);
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background .14s, color .14s;
}
.icon-btn:hover { background: var(--surface-3); color: var(--text); }
.icon-btn svg { width: 20px; height: 20px; }

/* O botao de tema mostra o icone da ACAO: no escuro o sol (ir pro claro).
   Usa as mesmas classes theme-light-only/theme-dark-only da logo. */

/* ---- Badges / alerts / callouts ---- */
.badge {
    display: inline-block;
    border-radius: 99px;
    padding: .1rem .55rem;
    font-size: .74rem;
    font-weight: 650;
    line-height: 1.5;
    vertical-align: middle;
    white-space: nowrap;
}
.badge-gold { background: var(--accent-soft); color: var(--accent-fg); border: 1px solid var(--accent-line); }
.badge-green { background: var(--ok-bg); color: var(--ok-text); border: 1px solid var(--ok-border); }
.badge-red { background: var(--err-bg); color: var(--err-text); border: 1px solid var(--err-border); }
.badge-muted { background: var(--surface-2); color: var(--muted); border: 1px solid var(--border-strong); }
/* plataforma: lilas, cor exclusiva desse dado — bate o olho e sabe de qual e */
.badge-plataforma {
    background: var(--plat-soft);
    color: var(--plat);
    border: 1px solid var(--plat-line);
    font-weight: 600;
}
/* Cor ESCOLHIDA em Plataformas › editar (sql/047): so troca os tres tokens que
   o `.badge-plataforma` ja usa — forma, peso e borda ficam iguais, so a cor
   muda. Sem classe = o lilas de sempre. */
.badge-plataforma.pc-azul    { --plat: var(--pc-azul);    --plat-soft: var(--pc-azul-soft);    --plat-line: var(--pc-azul-line); }
.badge-plataforma.pc-rosa    { --plat: var(--pc-rosa);    --plat-soft: var(--pc-rosa-soft);    --plat-line: var(--pc-rosa-line); }
.badge-plataforma.pc-laranja { --plat: var(--pc-laranja); --plat-soft: var(--pc-laranja-soft); --plat-line: var(--pc-laranja-line); }
.badge-plataforma.pc-verde   { --plat: var(--pc-verde);   --plat-soft: var(--pc-verde-soft);   --plat-line: var(--pc-verde-line); }
.badge-plataforma.pc-amarelo { --plat: var(--pc-amarelo); --plat-soft: var(--pc-amarelo-soft); --plat-line: var(--pc-amarelo-line); }

/* Escolha da cor (Plataformas › editar): cada opcao e o badge de verdade.
   Radio nativo (funciona sem JS); a opcao marcada ganha a moldura da marca. */
.cor-outras .badge-plataforma { margin: 0 .1rem .2rem 0; }
.cor-opcoes {
    border: 0; padding: 0; margin: 0 0 1rem;
    display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: .5rem;
}
.cor-opcao {
    display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .55rem;
    padding: .55rem .7rem; min-height: 44px;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--surface); cursor: pointer;
}
.cor-opcao:hover { border-color: var(--border-strong); }
.cor-opcao:has(input:checked) { border-color: var(--accent-line); background: var(--accent-soft); }
.cor-opcao:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.cor-opcao input { margin: 0; accent-color: var(--accent); }
.cor-nome { font-size: .82rem; color: var(--muted); }
/* o aviso fica numa linha propria: "parecida com a da Banca Geral" nao cabe ao lado */
.cor-aviso { flex: 1 1 100%; font-size: .74rem; color: var(--gold); line-height: 1.3; }

/* atendente do cliente: ciano, sempre em badge (regra do CLAUDE.md) */
.badge-atendente {
    background: var(--atend-soft);
    color: var(--atend);
    border: 1px solid var(--atend-line);
    font-weight: 600;
}
/* atencao/espera — dourado; badge-gold virou vermelho junto com a marca */
.badge-warn { background: rgba(180, 130, 10, .12); color: var(--gold); border: 1px solid rgba(180, 130, 10, .4); }

.alert {
    border-radius: var(--radius-sm);
    padding: .7rem 1rem;
    margin-bottom: 1rem;
    font-size: .92rem;
}
.alert-error { background: var(--err-bg); border: 1px solid var(--err-border); color: var(--err-text); }
.alert-success { background: var(--ok-bg); border: 1px solid var(--ok-border); color: var(--ok-text); }
/* `.alert-warn` era usado no HTML (atalhos, resultados) e NAO existia no CSS:
   saia sem fundo nem borda, ou seja, um aviso que nao avisa. Mesmos tons do
   `.badge-warn`, para amarelo continuar querendo dizer "atencao" no painel. */
.alert-warn { background: rgba(180, 130, 10, .12); border: 1px solid rgba(180, 130, 10, .4); color: var(--gold); }
.alert-warn a { color: inherit; }

/* informativo, NAO alerta: fundo neutro + barra da marca (com o accent
   vermelho, fundo tint inteiro seria lido como erro) */
.callout {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-left: 3px solid var(--accent);
    border-radius: var(--radius-sm);
    padding: .7rem 1rem;
    margin: 0 0 1.2rem;
    font-size: .92rem;
}
/* Variante para "este numero esta incompleto": mesma caixa, cor de aviso
   (dourado = atencao no painel, ver .alert-warn). Nao e erro nem alerta
   vermelho — e um limite do dado, e o operador precisa ver antes de decidir. */
.callout-alerta {
    border-left-color: var(--gold);
    background: rgba(180, 130, 10, .08);
}

/* ================= LOGIN ================= */
.login-page {
    min-height: 100dvh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.2rem;
    position: relative;
    overflow: hidden;
    background:
        radial-gradient(ellipse 60% 45% at 50% -5%, var(--accent-soft), transparent 70%),
        radial-gradient(ellipse 45% 35% at 85% 105%, var(--accent-soft), transparent 70%),
        var(--bg);
}

.login-theme {
    position: absolute;
    top: .8rem;
    right: .8rem;
    z-index: 2;
}

.login-bg { position: absolute; inset: 0; pointer-events: none; }
.login-bg .star {
    position: absolute;
    color: var(--accent);
    opacity: .18;
    animation: twinkle 4s ease-in-out infinite;
}
.login-bg .s1 { top: 12%; left: 14%; font-size: 14px; animation-delay: 0s; }
.login-bg .s2 { top: 26%; left: 78%; font-size: 20px; animation-delay: .7s; }
.login-bg .s3 { top: 64%; left: 8%;  font-size: 12px; animation-delay: 1.3s; }
.login-bg .s4 { top: 78%; left: 68%; font-size: 16px; animation-delay: 2s; }
.login-bg .s5 { top: 44%; left: 90%; font-size: 11px; animation-delay: 2.6s; }
.login-bg .s6 { top: 8%;  left: 52%; font-size: 12px; animation-delay: 3.1s; }
.login-bg .s7 { top: 88%; left: 30%; font-size: 18px; animation-delay: 1.8s; }
@keyframes twinkle {
    0%, 100% { opacity: .10; transform: scale(.9); }
    50% { opacity: .45; transform: scale(1.05); }
}

.login-card {
    position: relative;
    width: 100%;
    max-width: 400px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 2.2rem 2rem 2rem;
    box-shadow: var(--shadow-3);
}

.login-logo { text-align: center; margin-bottom: 1.7rem; }
.login-logo .brand-logo { width: min(262px, 84%); margin: 0 auto .55rem; }
.login-sub { margin: 0; color: var(--muted); font-size: .88rem; }

.login-card .field { margin-bottom: 1rem; }
.login-card .btn-primary { margin-top: .6rem; }

/* ================= FORMULARIOS ================= */
.field { margin-bottom: 1rem; min-width: 0; }
label {
    display: block;
    margin-bottom: .35rem;
    color: var(--muted);
    font-size: .84rem;
    font-weight: 600;
}
input[type="text"], input[type="password"], input[type="number"],
input[type="date"], input[type="email"], input[type="search"],
select, textarea {
    width: 100%;
    background: var(--bg-elev);
    color: var(--text);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    padding: .6rem .75rem;
    min-height: 42px;
    font: inherit;
    transition: border-color .15s, box-shadow .15s;
}
select {
    appearance: none;
    padding-right: 2.1rem;
    background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                      linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: right 1.05rem center, right .75rem center;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
}
input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}
input::placeholder { color: var(--faint); }
input[type="checkbox"], input[type="radio"] { accent-color: var(--accent); }

.field .hint, .hint { color: var(--muted); font-size: .8rem; margin: .35rem 0 0; }
.field-row { display: flex; gap: 1rem; flex-wrap: wrap; }
.field-row .field { flex: 0 0 auto; }
.field-row .field.grow { flex: 1 1 200px; }
.field-row.bottom { align-items: flex-end; }

/* ---- GRADE de formulario ----
   `.field-row` e flex, e cada linha reparte o espaco por conta propria: duas
   linhas seguidas com campos de larguras diferentes nao alinham coluna com
   coluna, e o formulario fica com os campos escalonados (Bruno, 08/09 — "esse
   formulario ta horroroso"). Numa GRADE as colunas sao as mesmas em todas as
   linhas por construcao, e a proxima pessoa que acrescentar um campo nao
   quebra o alinhamento sem perceber.
   Uma coluna no celular; a largura das colunas fica no modificador. */
.form-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0 1rem; }
.form-grid .field { min-width: 0; }
/* Num FORMULARIO o controle ocupa a largura do campo (`width: 100%` do estilo
   base). O combobox que o admin.js monta por cima do select e `inline-block` —
   dimensao pensada para a BARRA DE FILTRO, onde o campo tem a largura do
   controle. Dentro do `.field` ele precisa herdar a largura da coluna, senao
   sobra um controle curto no meio de um espaco vazio. */
.field > .sel-busca { display: block; width: 100%; }
@media (min-width: 901px) {
    /* lancamento: valor e curto, origem e destino dividem o resto */
    .form-grid.g-lancar { grid-template-columns: 190px minmax(0, 1fr) minmax(0, 1fr); }
    /* cadastro de centro: quem cresce e a DESCRICAO (o texto que liga o
       lancamento a conta); codigo e tipo tem tamanho conhecido */
    .form-grid.g-centro { grid-template-columns: 190px minmax(0, 1fr) 200px; }
    /* lista negra: o nome cresce; CPF e telefone tem tamanho conhecido */
    .form-grid.g-lista-negra { grid-template-columns: minmax(0, 1fr) 190px 190px; }
    /* limite do cassino: o valor e curto, o motivo cresce */
    .form-grid.g-limite { grid-template-columns: 220px minmax(0, 1fr); }
    .form-grid .span-2   { grid-column: span 2; }
    .form-grid .span-all { grid-column: 1 / -1; }
}
.form-actions {
    display: flex;
    justify-content: flex-end;
    gap: .6rem;
    margin-top: 1.2rem;
    padding-top: 1.1rem;
    border-top: 1px solid var(--border);
}
.checkbox-grid { display: flex; flex-wrap: wrap; gap: .5rem 1.4rem; }
.checkbox-item {
    display: flex; align-items: center; gap: .5rem;
    margin-bottom: 0; color: var(--text); font-weight: 500;
    cursor: pointer; min-height: 34px;
}
.checkbox-item input { width: 17px; height: 17px; }
.checkbox-item.muted { color: var(--muted); }
.override-form { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--border); }

/* ================= APP SHELL ================= */
.app { min-height: 100dvh; }
.shell { display: flex; min-height: 100dvh; }

/* ---- Topbar (mobile) ---- */
.topbar {
    display: none;
    position: sticky;
    top: 0;
    z-index: 40;
    height: var(--topbar-h);
    align-items: center;
    gap: .3rem;
    padding: 0 .5rem;
    background: var(--bg-elev);
    border-bottom: 1px solid var(--border);
}
.topbar-brand {
    display: flex;
    align-items: center;
    gap: .45rem;
    font-weight: 700;
    font-size: 1rem;
    margin-right: auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.topbar-brand { gap: .5rem; }

/* ---- Sidebar / drawer ---- */
.sidebar {
    width: var(--sidebar-w);
    flex-shrink: 0;
    background: var(--bg-elev);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100dvh;
}
.sidebar-brand {
    display: flex;
    align-items: center;
    gap: .55rem;
    padding: .85rem 1.15rem;
    border-bottom: 1px solid var(--border);
    min-height: var(--topbar-h);
}
.sidebar-brand .brand-logo { width: 156px; }
.sidebar-close { display: none; margin-left: auto; }

.sidebar-nav {
    flex: 1;
    padding: .7rem .55rem;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}
.nav-item {
    display: flex;
    align-items: center;
    gap: .7rem;
    padding: .6rem .75rem;
    margin-bottom: .12rem;
    border-radius: var(--radius-sm);
    color: var(--muted);
    text-decoration: none;
    font-weight: 550;
    font-size: .94rem;
    border-left: 2px solid transparent;
    transition: background .12s, color .12s;
}
.nav-item svg { width: 19px; height: 19px; flex-shrink: 0; }
.nav-item:hover { background: var(--surface-3); color: var(--text); }
.nav-item.active {
    background: var(--accent-soft);
    color: var(--accent-fg);
    border-left-color: var(--accent);
    font-weight: 650;
}
/* Contador de pendencia no item de menu (premio do cassino nao creditado).
   `margin-left:auto` joga para a direita sem mexer no icone + rotulo. */
.nav-item .nav-aviso { margin-left: auto; flex-shrink: 0; }
/* Bolinhas do item Transacoes (03/11): depositos (verde, entra) e saques
   (vermelho, sai) esperando — as contagens das abas (Areas::bolinhasMenu).
   CHEIAS, com o numero na cor do fundo do menu: o item ativo ja tem fundo
   avermelhado (accent-soft) e uma bolinha clara sumiria dentro dele.
   Contraste do numero: claro 6,8:1 (verde) e 7,8:1 (vermelho); escuro 11:1
   e 8:1. */
.nav-item .nav-counts { margin-left: auto; display: inline-flex; gap: 4px; flex-shrink: 0; }
.nav-count {
    min-width: 18px;
    padding: 0 5px;
    border-radius: 9px;
    text-align: center;
    color: var(--bg-elev);
    font-size: 10.5px; font-weight: 700; line-height: 17px;
    font-variant-numeric: tabular-nums;
}
.nav-count-in  { background: var(--ok-text); }
.nav-count-out { background: var(--err-text); }

.sidebar-user {
    border-top: 1px solid var(--border);
    padding: .75rem .9rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
}
.user-info { display: flex; flex-direction: column; align-items: flex-start; gap: .15rem; min-width: 0; }
.user-name { font-weight: 650; font-size: .9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-actions { display: flex; align-items: center; gap: .25rem; flex-shrink: 0; }
.sidebar-user form { margin: 0; }

/* ---- Scrim do drawer ---- */
.scrim {
    position: fixed;
    inset: 0;
    z-index: 45;
    background: var(--scrim);
    opacity: 0;
    visibility: hidden;
    transition: opacity .2s ease, visibility .2s;
}

/* ---- Conteudo ---- */
.main {
    flex: 1;
    min-width: 0;
    padding: 1.6rem 2rem 3rem;
}
.page-head { margin-bottom: 1.2rem; }
.page-head h1 { font-size: 1.5rem; margin: 0; }
.page-actions { margin-bottom: 1rem; display: flex; gap: .6rem; flex-wrap: wrap; }

/* ---- Filtros ---- */
.filter-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .8rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-1);
    padding: .8rem 1rem;
    margin-bottom: 1.3rem;
}
.filter-presets { display: flex; gap: .4rem; flex-wrap: wrap; }
.chip {
    display: inline-flex;
    align-items: center;
    min-height: 34px;
    padding: .25rem .85rem;
    border-radius: 99px;
    border: 1px solid var(--border-strong);
    background: var(--bg-elev);
    color: var(--muted);
    text-decoration: none;
    font-size: .85rem;
    font-weight: 550;
    white-space: nowrap;
}
.chip:hover { color: var(--text); background: var(--surface-3); }
.chip.active {
    background: var(--accent-soft);
    color: var(--accent-fg);
    border-color: var(--accent-line);
}
/* Faixa de chips que rola na horizontal (pendencias, proximas extracoes,
   proximas descargas). Vem do painel de controle, onde era o formato dos
   cards da home — no celular ela rola em vez de empilhar 24 linhas. */
.chip-strip {
    display: flex;
    gap: .4rem;
    flex-wrap: wrap;
    overflow-x: auto;
    padding-bottom: .15rem;
}
.chip-strip .chip { gap: .4rem; }
.chip-strip .chip .muted { font-weight: 500; font-size: .8rem; }
.chip-alerta { border-color: var(--err-border); background: var(--err-bg); color: var(--err-text); }
.chip-alerta:hover { background: var(--err-bg); color: var(--err-text); border-color: var(--red); }
.panel-alerta { border-left: 3px solid var(--red); }
/* Resultados (27/10): a pendencia de outro dia com o "dar baixa" (extracao que
   nao teve sorteio) dentro do chip, e a lista das baixas para desfazer. */
.pend-chip { gap: .4rem; }
.pend-chip a { color: inherit; text-decoration: none; display: inline-flex; gap: .4rem; align-items: baseline; }
.pend-chip form { display: inline; margin: 0; }
.pend-baixa {
    border: 0; background: transparent; color: inherit; font: inherit; font-size: .78rem;
    text-decoration: underline; text-underline-offset: 2px; cursor: pointer; padding: 0 0 0 .2rem; opacity: .85;
}
.pend-baixa:hover { opacity: 1; }
.pend-baixas { margin-top: .6rem; }
.pend-baixas summary { cursor: pointer; }
.pend-baixas ul { margin: .4rem 0 0; padding-left: 1.1rem; }
.pend-baixas li + li { margin-top: .25rem; }
/* Proximas extracoes: UMA linha com rolagem lateral (a borda some no fim
   para dizer que tem mais para o lado) */
.chip-strip.chip-rolagem {
    flex-wrap: nowrap; overflow-x: auto; scroll-snap-type: x proximity; padding-bottom: .4rem;
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent);
            mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent);
}
.chip-strip.chip-rolagem .chip { flex: 0 0 auto; scroll-snap-align: start; white-space: nowrap; }

/* `flex-end`: o campo agora tem rotulo em cima, entao ele e mais alto que o
   botao e que o filtro-multi — alinhar pelo centro deixava o "Filtrar" flutuando
   no meio da linha. Pela base, tudo termina no mesmo trilho. */
/* `flex: 1 1 auto` + `justify-content: flex-end`: a barra e `space-between`, e
   um contentor flex com `wrap` dentro de outro flex e medido pela LARGURA QUE
   ELE TERIA JA QUEBRADO — o navegador dava 475px a um conteudo de 550px e
   mandava o ultimo botao para a linha de baixo com 400px de sobra ao lado
   (medido em 08/09, 1400px de viewport). Recebendo o espaco que sobra, a barra
   so quebra quando falta espaco de verdade; `flex-end` mantem os campos
   encostados a direita, como eram. */
.filter-fields { display: flex; align-items: flex-end; justify-content: flex-end; gap: .5rem; flex-wrap: wrap; flex: 1 1 auto; }

/* ---- Campo de filtro com ROTULO VISIVEL ----
   Antes cada controle tinha so `aria-label`: o leitor de tela sabia o que era
   aquilo, o operador nao (Bruno, 30/08 — "tem alguns que esta sem uma label
   que ajuda a entender o que e aquela opcao"). O rotulo e o proprio texto do
   aria-label, encurtado onde ficaria comprido. */
/* `margin: 0` NAO e redundante: `.f-campo` e um <label>, e o estilo de
   formulario do painel da `margin-bottom: .35rem` a todo label. Com a barra
   alinhando pela BASE, essa margem entrava na conta da linha e os botoes
   ficavam 6px abaixo dos campos — em todas as telas com filtro (Bruno,
   31/08: "alguns botoes esta desalinhado, de varias paginas"). */
.f-campo { display: flex; flex-direction: column; gap: .15rem; min-width: 0; max-width: 100%; margin: 0; }
.f-cap {
    font-size: .68rem;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* As regras de largura abaixo eram do controle; com o rotulo, quem e item
   flex da barra passou a ser o `.f-campo` — sem mover isso, a busca deixava
   de esticar e o campo de ID deixava de encolher. */
/* `:has(> ...)` — filho DIRETO, nao descendente. O combobox com busca que o
   admin.js monta em select de 12+ opcoes poe um `input[type=search]` DENTRO do
   popup: com `:has()` solto, TODO campo de filtro que virasse combobox era
   confundido com o campo de busca e ganhava `flex: 1 1 180px`. Ele crescia,
   comia a linha e empurrava o botao seguinte para baixo — foi o que quebrou a
   barra da "Posicao de caixa" (Bruno, 08/09: "vc quebrou a linha so pra
   colocar o botao de imprimir"), e valia para toda tela com select grande. */
.filter-fields .f-campo:has(> input[type="search"]) { flex: 1 1 180px; min-width: 160px; }
.filter-fields .f-campo:has(> input.input-id) { flex: 0 0 7.5rem; min-width: 0; }
/* "Sem apostar ha / sem depositar ha" (dias) no ranking: numero curto, campo curto */
.filter-fields .f-campo:has(> input.input-dias) { flex: 0 0 8.5rem; min-width: 0; }
.filter-fields .f-campo input, .filter-fields .f-campo select { width: 100%; }
/* Um <select> sem largura declarada nasce do tamanho da MAIOR opcao: em
   "Posicao de caixa" a conta "Banco Banco Santander E" fazia o campo passar de
   400px e empurrar o "Imprimir" para a linha de baixo (Bruno, 08/09 — "vc
   quebrou a linha so pra colocar o botao de imprimir"). Aqui a lista de contas
   e conhecida e cabe em 230px; o texto que nao couber vira reticencia. */
.filter-fields .f-campo.f-lista { flex: 0 1 230px; min-width: 0; }
/* Campo de filtro NUNCA pode ser maior que a barra: em 320px o input de data e
   o select seguravam a largura minima e a PAGINA rolava de lado (medido em
   30/08: 334px de documento num viewport de 320). Encolher e feio; rolar a
   pagina inteira e pior. */
.filter-fields > *, .filter-presets > * { max-width: 100%; }
.filter-fields input, .filter-fields select { min-width: 0; }
.filter-fields input[type="date"] { width: auto; max-width: 100%; }
.filter-fields select { width: auto; min-width: 0; }
@media (min-width: 480px) { .filter-fields select { min-width: 150px; } }
/* `>` (filho DIRETO) e nao descendente: com o rotulo, o controle passou a
   viver dentro de um `.f-campo`, que e um flex de COLUNA — la dentro
   `flex: 1 1 180px` vira base de 180px no eixo VERTICAL e o campo de busca
   nasce com 180px de altura (medido: input de 180px numa barra de 356px).
   Quem carrega o flex agora e o `.f-campo`, nas regras logo acima; estas
   ficam para o controle que por acaso esteja solto na barra. */
.filter-fields > input[type="search"] { width: auto; flex: 1 1 180px; min-width: 160px; }
/* campos de ID sao curtos: nao devem roubar a linha do filtro.
   Precisa do seletor com elemento (`input.input-id`) para vencer a regra
   generica de input[type=search] acima, que tem a mesma especificidade. */
.filter-fields > input.input-id { flex: 0 0 7.5rem; width: 7.5rem; min-width: 0; }

/* ---- Filtro MULTI (dropdown de checkboxes) — 1o uso: modalidades e
   loterias do relatorio de jogos. <details> de proposito: abre/fecha sem JS
   (o admin.js so fecha no clique fora e atualiza o contador). O summary
   imita um <select> — mesma borda, altura e setinha — para a barra de
   filtros nao virar uma colecao de estilos. ---- */
.filtro-multi { position: relative; }
.filtro-multi > summary {
    list-style: none;
    cursor: pointer;
    user-select: none;
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    width: auto;
    min-width: 150px;
    min-height: 42px;
    background: var(--bg-elev);
    color: var(--text);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    padding: .6rem 2.1rem .6rem .75rem;
    font: inherit;
    background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                      linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: right 1.05rem center, right .75rem center;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
    transition: border-color .15s, box-shadow .15s;
}
.filtro-multi > summary::-webkit-details-marker { display: none; }
.filtro-multi[open] > summary,
.filtro-multi > summary:focus-visible {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}
/* contador de selecionados; vazio = "todas" (a ausencia de filtro) */
.filtro-multi .fm-badge {
    background: var(--accent);
    color: #fff;
    border-radius: 999px;
    font-size: .72rem;
    font-weight: 700;
    padding: .05rem .45rem;
}
.filtro-multi .fm-badge:empty { display: none; }
.filtro-multi .fm-painel {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 50;                /* acima do conteudo, abaixo do modal (60) */
    min-width: max(100%, 240px);
    max-height: 280px;
    overflow-y: auto;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-2);
    padding: .35rem;
}
.filtro-multi .fm-painel label {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .42rem .55rem;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: .88rem;
    white-space: nowrap;
}
.filtro-multi .fm-painel label:hover { background: var(--surface-2); }
.filtro-multi .fm-acoes {
    display: flex;
    gap: .4rem;
    padding: .3rem .35rem .45rem;
    border-bottom: 1px solid var(--border);
    margin-bottom: .3rem;
}
@media (max-width: 900px) {
    .filter-fields .filtro-multi { grid-column: 1 / -1; }
    .filtro-multi > summary { width: 100%; }
    .filtro-multi .fm-painel { position: static; min-width: 0; box-shadow: none; }
}

/* ---- Stat cards ---- */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(215px, 1fr));
    gap: .85rem;
    margin-bottom: 1.3rem;
}
/* CINCO cards numa linha so no desktop (Resultados, 27/10: com o "Ainda vao
   correr" o quinto caia sozinho na linha de baixo) */
.stat-grid.stat-grid-5 { grid-template-columns: repeat(auto-fill, minmax(min(175px, 100%), 1fr)); }
/* QUATRO por linha no desktop (pagina do afiliado, 29/10: os oito numeros em
   4 + 4, como o relatorio de referencia — o auto-fill quebrava 5 + 3). Abaixo
   disso volta o auto-fill de sempre. */
@media (min-width: 1100px) {
    .stat-grid.stat-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.stat-card {
    /* container query: valor grande (milhoes) diminui a fonte em vez de
       vazar do card — o nowrap acima impede quebrar "R$" do numero */
    container-type: inline-size;
    /* Todos os cards do mesmo tamanho, com ou sem rodape (Bruno, 04/08):
       o `min-height` iguala as linhas da grade e o rodape desce para a base
       (ver `.stat-foot`), senao um card com "estornos: ..." fica maior que os
       vizinhos e a grade vira escada. */
    min-height: 118px;
    position: relative;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-1);
    /* A reserva do icone e do ROTULO, nao do card: o icone fica na altura do
       titulo e o valor entra abaixo dele, entao tirar 45px da largura util do
       numero (26% do card no celular) era desperdicio — foi o que fez
       "R$ 3.716.166,74" vazar 42px no mes cheio. */
    padding: 1rem 1.1rem;
    display: flex;
    flex-direction: column;
    gap: .2rem;
}
/* destaque = barra da marca na lateral; fundo continua neutro para o numero
   nao parecer alerta */
.stat-card.highlight {
    border-color: var(--border-strong);
    box-shadow: var(--shadow-1), inset 3px 0 0 var(--accent);
    padding-left: calc(1.1rem + 3px);
}
.stat-label {
    color: var(--muted);
    font-size: .76rem;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: .05em;
    line-height: 1.25;
    /* duas linhas SEMPRE reservadas: com o titulo curto o valor comecaria mais
       alto que o do card vizinho de titulo longo ("Depositos - Saques") e a
       linha de numeros ficava em degrau. O 2.6em (e nao 2.5) da a folga que
       mantem o valor ABAIXO do icone agora que ele usa a largura inteira. */
    min-height: 2.6em;
}
/* Aqui, sim, o icone come largura — ele fica ao lado do titulo. So no card
   que TEM icone: a visao por produto nao usa `stat_icone()` e a reserva a toa
   quebrava "Premios pagos" em duas linhas sem motivo. */
.stat-card:has(.stat-ic) .stat-label { padding-right: 2.6rem; }
.stat-value { font-size: 1.5rem; font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: -.02em; white-space: nowrap; }
/* a QUANTIDADE do total ("1.234 depositos"), logo abaixo do valor e menor que
   ele (Bruno, 24/09): o valor continua sendo o numero do card */
.stat-qtd { font-size: .92rem; font-weight: 600; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; line-height: 1.2; }
/* A regra do tamanho unico vale com a linha nova: 125px e o card mais alto
   medido no Chrome em 24/09 (rotulo + valor + rodape, o "Ver os cadastros";
   rotulo + valor + quantidade da 119). O rodape "estornos" saiu dos cards no
   mesmo dia — virou uma linha embaixo da grade. So na grade que TEM
   quantidade: as outras telas com `.stat-card` continuam com a altura delas. */
.stat-grid:has(.stat-qtd) .stat-card { min-height: 125px; }
/* rodape colado na base: cards com e sem rodape terminam na mesma linha */
.stat-foot { font-size: .78rem; margin-top: auto; padding-top: .25rem; }
/* ---- Icone do card (identificacao, uma cor por metrica) ----
   Fica no canto, fora do fluxo, para nao disputar largura com o numero.
   O fundo e a propria cor a 12% (color-mix com currentColor), entao cada
   variacao abaixo so precisa dizer a cor. */
.stat-ic {
    position: absolute;
    top: .9rem;
    right: .9rem;
    width: 34px;
    height: 34px;
    border-radius: 10px;
    display: grid;
    place-items: center;
    background: color-mix(in srgb, currentColor 12%, transparent);
}
.stat-ic svg { width: 18px; height: 18px; }
.ic-green { color: var(--green); }
.ic-red   { color: var(--red); }
.ic-gold  { color: var(--gold); }
/* dois tons novos, so para icone de card: azul da aposta e rosa do premio.
   Validados com o script da skill dataviz contra verde/vermelho/dourado
   (claro: todos os pares >= 15 ΔE em visao normal; o pior par em deuteranopia
   e dourado x rosa, 7.9 — banda de piso, aceitavel porque o titulo escrito e
   o desenho do icone carregam a identidade, a cor so ajuda a achar). */
.ic-blue,
.col-jog  { color: #1d4ed8; }
.ic-pink,
.col-pre  { color: #be185d; }
.ic-slate { color: #64748b; }
:root[data-theme="dark"] .ic-blue,  .theme-dark .ic-blue,
:root[data-theme="dark"] .col-jog,  .theme-dark .col-jog  { color: #93b4ff; }
:root[data-theme="dark"] .ic-pink,  .theme-dark .ic-pink,
:root[data-theme="dark"] .col-pre,  .theme-dark .col-pre  { color: #f9a8d4; }
:root[data-theme="dark"] .ic-slate, .theme-dark .ic-slate { color: #cbd5e1; }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .ic-blue,
    :root:not([data-theme="light"]) .col-jog  { color: #93b4ff; }
    :root:not([data-theme="light"]) .ic-pink,
    :root:not([data-theme="light"]) .col-pre  { color: #f9a8d4; }
    :root:not([data-theme="light"]) .ic-slate { color: #cbd5e1; }
}

/* ================= GRAFICOS =================
   Desenhados no servidor (SVG + HTML). O SVG usa viewBox 0..100 esticado
   (preserveAspectRatio=none) para caber em qualquer largura; por isso o
   traco leva vector-effect e os marcadores/barras sao HTML — assim nao
   deformam. Texto NUNCA usa a cor da serie (regra da leitura). */
.chart-grid {
    display: grid;
    /* min(400px,100%): sem o min(), a coluna nao encolhe abaixo de 400px e
       estoura a tela no celular */
    grid-template-columns: repeat(auto-fit, minmax(min(400px, 100%), 1fr));
    gap: 1.3rem;
    margin-bottom: 1.3rem;
}
.chart-grid .panel { margin-bottom: 0; }

.chart { margin: 0; --y-w: 54px; --plot-h: 190px; }

.chart-legend {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem 1.1rem;
    margin-bottom: .7rem;
    font-size: .84rem;
    color: var(--muted);
}
.legend-item { display: inline-flex; align-items: center; gap: .4rem; }
.legend-item strong { color: var(--text); font-variant-numeric: tabular-nums; font-weight: 650; }
/* chave espelha a marca: traco para linha (tracejado no saque), bloco para barra */
.legend-key { width: 16px; border-top: 2px solid; border-radius: 2px; }
.key-in { border-color: var(--chart-in); }
.key-out { border-color: var(--chart-out); border-top-style: dashed; }
.legend-key.key-rect { width: 12px; height: 12px; border: 0; border-radius: 3px; }
.key-rect.key-in { background: var(--chart-in); }
.key-rect.key-out { background: var(--chart-out); }
.key-rect.key-neutral { background: var(--chart-neutral); }

.chart-plot { position: relative; height: var(--plot-h); }
.chart-plot:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 4px; }
.chart-canvas { position: absolute; inset: 0 6px 0 var(--y-w); }

.chart-svg { width: 100%; height: 100%; display: block; overflow: visible; }
.chart-gridlines line {
    stroke: var(--border);
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
}

.chart-y { position: absolute; left: 0; top: 0; bottom: 0; width: var(--y-w); }
.chart-y span {
    position: absolute;
    right: 8px;
    transform: translateY(-50%);
    font-size: .68rem;
    color: var(--faint);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.chart-area { stroke: none; }
.area-in { fill: var(--chart-in); opacity: .10; }
.area-out { fill: var(--chart-out); opacity: .10; }
.chart-line { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.line-in { stroke: var(--chart-in); }
/* tracejado = 2o canal de identidade (o par verde/vermelho e fraco em CVD) */
.line-out { stroke: var(--chart-out); stroke-dasharray: 5 4; }

.chart-dot {
    position: absolute;
    width: 9px; height: 9px;
    margin: -4.5px 0 0 -4.5px;
    border-radius: 50%;
    box-shadow: 0 0 0 2px var(--surface);
}
.dot-in { background: var(--chart-in); }
.dot-out { background: var(--chart-out); }

.chart-cross {
    position: absolute;
    top: 0; bottom: 0;
    width: 1px;
    background: var(--border-strong);
    pointer-events: none;
}

/* marcador do ponto sob o ponteiro (anel na cor da superficie) */
.chart-hot {
    position: absolute;
    width: 9px; height: 9px;
    margin: -4.5px 0 0 -4.5px;
    border-radius: 50%;
    box-shadow: 0 0 0 2px var(--surface);
    pointer-events: none;
}
.hot-in { background: var(--chart-in); }
.hot-out { background: var(--chart-out); }

.chart-zero {
    position: absolute;
    left: 0; right: 0;
    height: 1px;
    background: var(--border-strong);
}

/* ---- Barras (GGR) ---- */
.bars { position: absolute; inset: 0; display: flex; gap: 2px; }
.bar-slot { position: relative; flex: 1 1 0; min-width: 0; }
.bar {
    position: absolute;
    left: 0; right: 0;
    max-width: 24px;
    margin-inline: auto;
    height: var(--h);
    min-height: 1px;
}
.bar-pos { bottom: calc(100% - var(--zero)); background: var(--chart-in); border-radius: 4px 4px 0 0; }
.bar-neg { top: var(--zero); background: var(--chart-out); border-radius: 0 0 4px 4px; }
.bar-slot:hover .bar, .bar-slot.on .bar { filter: brightness(1.18); }

/* Barra de CONTAGEM empilhada (cadastros do dia x quantos depositaram):
   o neutro e a barra inteira e o verde e a parte convertida, desenhada por
   cima a partir da mesma base. O `.sep` poe 2px da superficie entre os dois
   preenchimentos — sem isso o olho le uma barra so, de duas cores. */
.bar-neutro { bottom: 0; background: var(--chart-neutral); border-radius: 4px 4px 0 0; }
.bar-conv   { bottom: 0; background: var(--chart-in); border-radius: 4px 4px 0 0; }
.bar-conv.sep { box-sizing: border-box; border-top: 2px solid var(--surface); }

/* ---- Eixo X ---- */
.chart-x {
    display: flex;
    padding: .45rem 6px 0 var(--y-w);
    font-size: .68rem;
    color: var(--faint);
    font-variant-numeric: tabular-nums;
}
.chart-x span { flex: 1 1 0; min-width: 0; text-align: center; white-space: nowrap; }
.chart-x span.hide { visibility: hidden; }
.chart-x span:first-child { text-align: left; }
.chart-x span:last-child { text-align: right; }

/* ---- Tooltip ---- */
.chart-tip {
    position: absolute;
    z-index: 5;
    transform: translate(-50%, -112%);
    background: var(--bg-elev);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-2);
    padding: .45rem .6rem;
    font-size: .78rem;
    line-height: 1.45;
    white-space: nowrap;
    pointer-events: none;
}
.chart-tip .tip-when { color: var(--muted); font-size: .72rem; margin-bottom: .15rem; }
.chart-tip .tip-row { display: flex; align-items: center; gap: .4rem; }
/* valor manda, nome da serie e secundario */
.chart-tip .tip-row strong { color: var(--text); font-variant-numeric: tabular-nums; }
.chart-tip .tip-row span { color: var(--muted); }

.chart-empty { text-align: center; padding: 3.2rem 1rem; margin: 0; }

/* ---- Tabela equivalente (o numero nunca fica so no hover) ---- */
.chart-table {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-1);
    padding: .3rem 1.1rem;
    margin-bottom: 1.3rem;
}
.chart-table summary {
    cursor: pointer;
    padding: .55rem 0;
    font-size: .88rem;
    font-weight: 600;
    color: var(--muted);
}
.chart-table summary:hover { color: var(--text); }
.chart-table[open] summary { margin-bottom: .4rem; }

/* ---- Animacao de entrada ----
   O traco entra por um clip que abre da esquerda para a direita. Nao da pra
   usar stroke-dashoffset aqui: o dasharray ja carrega o tracejado do saque,
   que e o canal extra de identidade. */
@keyframes chart-wipe { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes chart-fade { from { opacity: 0; } to { opacity: 1; } }
/* termina na opacidade real da area (10%) — um fade ate 1 viraria bloco */
@keyframes chart-fade-area { from { opacity: 0; } to { opacity: .10; } }
@keyframes bar-grow { from { transform: scaleY(0); } to { transform: scaleY(1); } }

.chart-reveal {
    transform-box: fill-box;
    transform-origin: left center;
    animation: chart-wipe 1s cubic-bezier(.25, .8, .35, 1) both;
}
.chart-area { animation: chart-fade-area .7s ease-out .3s both; }
.chart-dot { animation: chart-fade .35s ease-out .9s both; }
.bar {
    animation: bar-grow .5s cubic-bezier(.2, .8, .3, 1) both;
    animation-delay: calc(var(--i) * 16ms);
}
.bar-pos { transform-origin: bottom center; }
.bar-neg { transform-origin: top center; }

/* ---- Paineis / tabelas ---- */
.panel {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-1);
    padding: 1.1rem 1.25rem;
    margin-bottom: 1.3rem;
}
.panel h2 { font-size: 1.05rem; margin-bottom: .8rem; }
.panel-form { max-width: 760px; }
.panel-form.panel-wide { max-width: none; }
.section-title { font-size: 1rem; margin: 1.5rem 0 .7rem; }
.section-title:first-child { margin-top: 0; }

/* `position: relative` NAO e decoracao: sem ele, filho ABSOLUTO da tabela
   (o `.sr-only` do cabecalho da coluna de acoes) tem como bloco de contencao o
   documento, escapa do recorte e estica a PAGINA. Medido em 30/08 na tela de
   jogadores: html.scrollWidth 1596 num viewport de 1440 — a pagina rolava na
   horizontal e levava a sidebar junto. Com o relative: 1440, e quem rola passa
   a ser a tabela, que era a intencao. */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; position: relative; }
table { width: 100%; border-collapse: collapse; font-size: .92rem; }
th, td { text-align: left; padding: .6rem .7rem; border-bottom: 1px solid var(--border); vertical-align: middle; }
th {
    color: var(--muted);
    font-size: .74rem;
    text-transform: uppercase;
    letter-spacing: .05em;
    font-weight: 700;
    white-space: nowrap;
}
tbody tr:hover { background: var(--row-hover); }
tbody tr:last-child td { border-bottom: 0; }
/* valor/numero nunca quebra em duas linhas */
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
th.center, td.center { text-align: center; }
/* acoes da linha: mesma largura em todas as linhas — coluna alinhada le
   melhor do que botao "do tamanho da palavra" */
.row-actions { display: flex; gap: .4rem; justify-content: flex-end; align-items: center; flex-wrap: wrap; }
.row-actions form { margin: 0; }
.row-actions .btn { min-width: 108px; }
.row-actions .btn svg { width: 14px; height: 14px; }

/* ALINHAMENTO DAS LINHAS (Bruno, 04/08: "fica desalinhando os valores").
   Numa listagem, uma celula com sub-linha (R$ 1.681,00 + "10x") e mais alta
   que as de uma linha so; com o `vertical-align: middle` padrao, a celula
   curta ficava centralizada NO MEIO das duas linhas da vizinha e cada valor
   da mesma linha parava numa altura diferente — varrer seis colunas de
   dinheiro assim e cansativo. `baseline` poe a PRIMEIRA linha de todas as
   celulas na mesma linha de base, independente de fonte e line-height.
   Botao de acao continua no meio: ele nao tem linha de base para casar. */
.table-cards td { vertical-align: baseline; }
.table-cards td.row-actions { vertical-align: middle; }

/* Celula com duas informacoes: a principal e a de apoio embaixo. Junta
   colunas relacionadas (loteria+tipo, modalidade+numeros) e deixa a tabela
   com menos colunas para ler. */
.cel-main { display: block; font-weight: 600; line-height: 1.35; }
.cel-sub {
    display: block;
    color: var(--muted);
    font-size: .78rem;
    line-height: 1.35;
}
.cel-sub.mono { font-size: .74rem; }
/* e-mail e afins: corta com reticencias em vez de alargar a coluna (o valor
   inteiro fica no `title`, e no cartao do celular a largura e a da tela) */
.cel-sub.corta { max-width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* o e-mail na celula do jogador (`jogador_email`) sai INTEIRO, numa linha so,
   e a coluna cresce na horizontal para ele caber. A 1a versao (19/10) cortava
   com reticencias para nao alargar o ranking e foi reprovada no mesmo dia:
   "nao ta dando pra ver o email, faz crescer na horizontal ao inves de tentar
   fazer caber". */
.cel-sub.cel-email { white-space: nowrap; }
/* chave PIX aleatoria tem 36 caracteres sem espaco: quebra em vez de alargar a coluna */
.cel-pix { overflow-wrap: anywhere; }
/* "22:49 · ha 15 h" nao pode quebrar entre o numero e a unidade */
.cel-sub.inteiro { white-space: nowrap; }
/* "cadastro 12/03/2026" (`jogador_cadastro`): uma linha so; conta de menos de
   7 dias em negrito na cor do texto — sem cor nova, que aqui ja tem verde,
   vermelho e dourado dizendo dinheiro */
.cel-sub.cel-cadastro { white-space: nowrap; }
.cel-sub.cel-cadastro.is-novo { color: var(--text); font-weight: 600; }

/* Tabela de 9 colunas (novos cadastros): com a calha padrao de .7rem ela
   passava 115px da largura do painel em 1400px e a coluna de acao ficava
   cortada. So a calha encolhe — altura de linha e fonte continuam iguais. */
.tabela-densa th, .tabela-densa td { padding-inline: .5rem; }
td.num .cel-main, td.num .cel-sub { text-align: right; }
.cel-sub.green { color: var(--green); font-weight: 600; }
.cel-sub.gold { color: var(--gold); font-weight: 600; }
/* atendente + plataforma empilhados na mesma coluna */
/* cabecalho composto pode usar duas linhas — nao vale alargar a coluna
   inteira so por causa do titulo */
th.th-2l { white-space: normal; line-height: 1.25; }

.cel-badges { display: inline-flex; flex-direction: column; gap: .22rem; align-items: flex-start; }

/* ---- Ranking: cabecalho que ordena + posicao ---- */
/* A coluna clicada e a que manda no ranking, entao ela fica marcada nos dois
   lugares: no cabecalho (seta) e na coluna inteira (fundo levissimo) — sem
   isso a tabela de seis numeros nao diz por qual deles esta ordenada. */
th.th-sort { padding: 0; }
th.th-sort a {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: .3rem;
    padding: .6rem .7rem;
    color: inherit;
    text-decoration: none;
    white-space: nowrap;
}
th.th-sort a:hover { color: var(--text); background: var(--row-hover); }
th.th-sort.is-active a { color: var(--accent-fg); }
.sort-arrow { font-size: .6em; line-height: 1; }
td.is-sorted { background: var(--surface-2); }
tbody tr:hover td.is-sorted { background: var(--row-hover); }

.rank-col { width: 1%; }
.rank { color: var(--muted); font-weight: 700; font-variant-numeric: tabular-nums; }

/* Grupos do ranking (05/10, "melhorar a visualizacao" no desktop): 16 colunas
   de numero sem ritmo nenhum cansavam a leitura. Rotulo em cima de cada grupo
   (dinheiro / jogo / resultado / dias sem), com um traco que para antes da
   borda — os tracos de grupos vizinhos nao se emendam — e uma divisoria na
   primeira coluna (`g-ini`). So no desktop: no celular o cabecalho some e o
   cartao ja separa linha a linha. */
@media (min-width: 901px) {
    .tabela-ranking .g-ini { border-left: 1px solid var(--border); }
    .tabela-ranking tr.grupos th { border-bottom: 0; padding-top: .45rem; padding-bottom: .3rem; }
    .tabela-ranking th.grupo {
        text-align: center;
        font-size: .66rem;
        letter-spacing: .08em;
        background: linear-gradient(var(--border-strong), var(--border-strong)) center bottom / calc(100% - 1rem) 1px no-repeat;
    }
}

/* A COLUNA DE ACAO VOLTA A SER CELULA DE TABELA NO DESKTOP (Bruno, 08/08:
   "ficou uma linha embaixo desalinhada em todas as tela").

   `td { display: flex }` tira a celula da tabela: o navegador a embrulha numa
   celula anonima e o `border-bottom` fica no bloco flex, que so tem a altura
   dos botoes. Resultado: numa linha alta (as outras colunas tem sub-linha) a
   divisoria da acao aparece **no meio da linha**, solta, e nao acompanha o
   trilho das demais. Com `table-cell` a celula estica com a linha e a borda
   volta para o lugar — de quebra o `vertical-align` passa a valer.

   Como o flex sai de cena aqui, o que alinhava os botoes vira: `text-align`
   para encostar a direita, `inline-block` no <form> (senao cada acao vira uma
   linha) e margem no lugar do `gap`. No celular o cartao continua com o flex. */
@media (min-width: 901px) {
    /* O `th` tambem: a classe `.row-actions` e a mesma nos dois, e um `th` em
       `display: flex` nao e celula de tabela — ele nao estica ate a altura da
       linha e a BORDA de baixo dele fica 18px mais alta que a das vizinhas.
       Na tela era o traco do cabecalho subindo em degrau na coluna dos botoes
       (Bruno, 31/08). So aparecia onde o cabecalho da coluna de acao existe
       (hoje as duas telas de Marketing), mas a correcao e geral: cabecalho
       novo de coluna de acao ja nasce certo. */
    th.row-actions { display: table-cell; }
    td.row-actions { display: table-cell; text-align: right; white-space: nowrap; }
    td.row-actions > form { display: inline-block; }
    td.row-actions > *, td.row-actions > form > .btn { vertical-align: middle; }
    td.row-actions > * + * { margin-left: .2rem; }
}

/* ================= PERFIL DO JOGADOR ================= */
.player-head { padding-bottom: .9rem; }
.ph-top { display: flex; flex-wrap: wrap; gap: 1rem 2rem; justify-content: space-between; align-items: flex-start; }
.ph-name { font-size: 1.35rem; margin: 0; letter-spacing: -.01em; }
.ph-sub { margin: .1rem 0 .55rem; font-size: .9rem; }
.ph-badges { flex-direction: row; flex-wrap: wrap; gap: .35rem; }

/* saldo: o total manda, os baldes explicam de onde ele vem */
.ph-saldo { text-align: right; margin-left: auto; }
.ph-saldo .stat-value { font-size: 1.7rem; display: block; }
.saldo-baldes {
    list-style: none;
    margin: .45rem 0 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: .2rem .9rem;
    font-size: .78rem;
    font-variant-numeric: tabular-nums;
}
/* Os saldos um a um (jogadores/_saldos.php, 31/10): o quadro encosta na
   direita como o total; saldo zerado sai apagado, como no ranking. */
.saldo-quadro { margin: .5rem 0 0 auto; border-collapse: collapse; font-size: .78rem; text-align: left; }
.saldo-quadro th {
    color: var(--muted); font-size: .66rem; text-transform: uppercase; letter-spacing: .05em;
    font-weight: 650; padding: 0 .5rem .25rem; border-bottom: 1px solid var(--border);
}
.saldo-quadro td { padding: .25rem .5rem; border-bottom: 1px solid var(--border); vertical-align: top; }
.saldo-quadro tr:last-child td { border-bottom: 0; }
.saldo-quadro td:first-child { font-weight: 600; white-space: nowrap; }
.saldo-quadro tr.is-zero td { color: var(--muted); font-weight: 400; }
.saldo-usar {
    display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .2rem .8rem;
    margin: .5rem 0 0; font-size: .78rem; font-variant-numeric: tabular-nums;
}
.saldo-usar-item.is-zero strong { color: var(--muted); font-weight: 500; }
.saldo-transf { max-width: 36rem; margin: .35rem 0 0 auto; font-size: .78rem; }
@media (max-width: 640px) {
    .ph-saldo { text-align: left; margin-left: 0; width: 100%; }
    .saldo-quadro { width: 100%; margin-left: 0; }
    .saldo-quadro th, .saldo-quadro td { padding-left: .3rem; padding-right: .3rem; }
    .saldo-quadro td:first-child { white-space: normal; }
    .saldo-usar { justify-content: flex-start; }
    .saldo-transf { margin-left: 0; }
    .ph-enviar { align-items: flex-start; }
}

.ph-meta {
    display: flex;
    flex-wrap: wrap;
    gap: .55rem 2rem;
    margin: 1rem 0 0;
    padding-top: .9rem;
    border-top: 1px solid var(--border);
}
.ph-meta dt { color: var(--muted); font-size: .7rem; text-transform: uppercase; letter-spacing: .05em; font-weight: 650; }
/* `anywhere`: e-mail e chave PIX compridos quebram em vez de passar da tela no celular */
.ph-meta dd { margin: .1rem 0 0; font-size: .88rem; overflow-wrap: anywhere; }
.ph-actions { display: flex; flex-wrap: wrap; gap: .45rem; margin-top: .9rem; align-items: center; }
.ph-actions form { margin: 0; }
/* Trocar senha (04/10): botao e campo num bloco so — aberto, o campo vem logo
   depois do botao, na mesma linha, e o bloco quebra inteiro quando nao cabe.
   O campo tem a altura do .btn-sm (o input padrao tem 42px e destoava da
   fileira). O botao aberto NAO ganha o tom do chip ativo: o vermelho claro
   confundia com o "Entrar com acesso total" ao lado. */
.ph-senha { display: flex; flex-wrap: wrap; gap: .45rem; align-items: center; }
.ph-senha-form { display: flex; flex-wrap: wrap; gap: .45rem; align-items: center; }
.ph-senha-form input[type="text"] { width: 190px; min-height: 34px; padding: .3rem .6rem; font-size: .84rem; }
/* Enviar saldo (14/10, sql/056): mora no cartao do saldo, alinhado a direita
   como ele; fechado e so o botao. Aberto, os campos quebram em linhas e no
   celular cada um ocupa a largura toda (o cartao vira coluna). Mesma altura
   de campo do Trocar senha. */
.ph-enviar { display: flex; flex-direction: column; align-items: flex-end; gap: .45rem; margin-top: .5rem; }
.ph-enviar-form { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: .45rem; max-width: 460px; }
.ph-enviar-form input[type="text"],
.ph-enviar-form select { min-height: 34px; padding: .3rem .6rem; font-size: .84rem; }
.ph-enviar-form input[name="valor"] { width: 150px; flex: 0 0 150px; }
/* o select global e width:100% — aqui ele divide a linha com o valor */
.ph-enviar-form select { width: auto; flex: 0 1 250px; }
.ph-enviar-form input[name="motivo"] { flex: 1 1 220px; }
.ph-enviar-sino { display: inline-flex; align-items: center; gap: .3rem; font-size: .8rem; color: var(--muted); }
@media (max-width: 640px) {
    .ph-enviar { align-items: stretch; }
    .ph-enviar-form { max-width: none; justify-content: stretch; }
    .ph-enviar-form input[type="text"], .ph-enviar-form select { flex: 1 1 100%; width: auto; }
}
.ph-imp-log { margin: .7rem 0 0; }

/* ---- Abas da ficha do jogador ----
   Mesma pilula do app do jogador ("Minhas Apostas | Minhas Transacoes"): a
   ativa e um bloco cheio na cor da marca. O numero de abas varia com a
   permissao do admin (hoje ate seis: Resumo, Apostas, Transacoes, Historico,
   Cadastro e Bloqueios). */
.tabs {
    display: grid;
    /* uma linha so, qualquer numero de abas em colunas iguais */
    grid-auto-flow: column;
    /* minmax(0, 1fr) e nao 1fr: com `1fr` o minimo e o min-content, entao um
       rotulo longo (ou fonte grande do sistema no celular) empurra a barra
       para fora da tela em vez de encolher. */
    grid-auto-columns: minmax(0, 1fr);
    gap: 6px;
    margin-bottom: 1.3rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 4px;
}
.tab {
    padding: 10px 14px;
    min-height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
    color: var(--muted);
    text-decoration: none;
    font-size: .86rem;
    font-weight: 600;
    white-space: nowrap;
    /* com o minmax(0,1fr) da barra, o rotulo longo corta com reticencias em
       vez de empurrar a pagina — no celular a aba estreita e melhor do que a
       tela inteira rolando de lado */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    display: block;
    text-align: center;
    line-height: 20px;
}
/* Fora do desktop a fila unica nao cabe: com OITO abas (a de Atendimento
   entrou em 16/09) sobram ~45px para cada uma no celular e "Transacoes" vira
   "Tran…". A barra quebra em linhas — ela nao rola de lado de proposito (a
   ficha ja tem rolagem vertical longa; rolagem lateral escondida esconderia
   aba).

   Tres faixas, porque o rotulo mais longo ("Atendimento", 11 caracteres) e
   quem manda:
     - tablet/janela media: 4 por linha (165px cada em 700px — folgado);
     - celular: 3 por linha em 110px, o que so cabe com a fonte e o respiro
       lateral menores — medido no Chrome a 390px, e o que impede o
       "Atendimen…" da primeira versao. */
@media (max-width: 900px) {
    .tabs {
        grid-auto-flow: row;
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}
@media (max-width: 640px) {
    .tabs { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .tab {
        font-size: .78rem;
        padding: 10px 4px;
        /* letra menor pede menos espaco entre palavras vizinhas, senao duas
           abas curtas parecem uma so */
        letter-spacing: -.01em;
    }
}

.tab:hover { color: var(--text); background: var(--bg-elev); }
.tab.active,
.tab.active:hover { background: var(--accent); color: #fff; }

/* ABAS EM GRUPOS (26/10, "ta ficando muito apertado muito grande"): os cinco
   grupos cabem numa linha so em qualquer tela — as faixas de 4 e de 3 por
   linha acima eram para as NOVE abas. No celular cada grupo fica com a largura
   do rotulo (flex), senao "Atendimento" cortaria num quinto de 390px. */
@media (max-width: 900px) {
    .tabs.tabs-grupos { grid-auto-flow: column; grid-template-columns: none; }
}
@media (max-width: 640px) {
    .tabs.tabs-grupos { display: flex; gap: 4px; }
    .tabs.tabs-grupos .tab { flex: 1 1 auto; padding: 10px 6px; }
}
/* A linha das abas do grupo aberto: chips (o mesmo componente dos filtros
   "Hoje / 7 dias"), menores que os grupos e logo abaixo deles — o vermelho
   cheio fica so no grupo, a aba ativa usa o tom suave do chip. */
.subtabs {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    margin: -.7rem 0 1.2rem;
    padding: 0 .25rem;
}

/* ---- Orientacoes (aba do grupo Atendimento, sql/065) ---- */
.orient-topo { display: flex; align-items: baseline; justify-content: space-between; gap: .5rem; }
.orient-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: .5rem;
}
.orient-item {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
    padding: .6rem .75rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-elev);
    cursor: pointer;
    min-width: 0;
}
.orient-item:hover { border-color: var(--border-strong); }
.orient-item.is-on { border-color: var(--accent-line); background: var(--accent-soft); }
.orient-item input[type="checkbox"] {
    width: 18px; height: 18px; margin: .1rem 0 0; flex: 0 0 auto;
    accent-color: var(--accent);
}
.orient-txt { display: flex; flex-direction: column; min-width: 0; }
.orient-nome { font-weight: 600; font-size: .9rem; overflow-wrap: break-word; }
.orient-quem { font-size: .74rem; color: var(--muted); }
.orient-nova { display: flex; gap: .5rem; flex-wrap: wrap; }
.orient-nova input[type="text"] { flex: 1 1 220px; min-width: 0; }
.orient-ren { display: flex; gap: .4rem; align-items: center; }
.orient-ren input[type="text"] { flex: 1 1 auto; min-width: 0; }
.orient-sum { cursor: pointer; font-weight: 600; }
@media (max-width: 640px) {
    /* dois por linha no celular: doze itens numa coluna so viram uma lista longa */
    .orient-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .orient-item { padding: .55rem .6rem; gap: .5rem; }
    /* no cartao da lista, o campo de renomear ocupa a linha (o rotulo fica em cima) */
    .table-cards td .orient-ren { flex: 1 1 100%; }
}

.sub-title { font-size: .82rem; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; margin: 1.4rem 0 .7rem; }
.sub-title:first-child { margin-top: 0; }
.split-3 {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
    gap: 1.4rem 2rem;
}

/* ---- Cassino por titulo (ficha do jogador) ----
   Cartao com a CAPA do jogo — a mesma arte que o jogador ve no app. Nome de
   jogo de cassino nao se decora ("20013"), a arte se reconhece na hora.
   O ladrilho com as iniciais fica atras da imagem: jogo sem arte no pacote da
   OMG (68 de 1.239) e imagem que nao carregou caem nele sozinhos. */
.jogo-grid {
    list-style: none; margin: 0; padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(230px, 100%), 1fr));
    gap: .8rem;
}
.jogo-card {
    display: flex; gap: .7rem; align-items: stretch;
    padding: .55rem; border: 1px solid var(--border); border-radius: 10px;
    background: var(--surface-2); min-width: 0;
}
.jogo-thumb {
    position: relative; flex: 0 0 auto;
    width: 54px; height: 72px; border-radius: 7px; overflow: hidden;
    background: var(--surface-3);
}
.jogo-thumb img {
    position: absolute; inset: 0;
    width: 100%; height: 100%; object-fit: cover; display: block;
}
/* Capa de reserva (05/11/2026): fundo colorido + 🎰, cor pelo game_id
   (`CassinoJogos::ladrilho`). Era o ladrilho cinza com as iniciais. */
.jogo-ladrilho {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.75rem; line-height: 1;
    background: var(--capa-luz), var(--capa-1);
    text-shadow: 0 2px 6px var(--capa-sombra);
}
.jogo-ladrilho.capa-2 { background: var(--capa-luz), var(--capa-2); }
.jogo-ladrilho.capa-3 { background: var(--capa-luz), var(--capa-3); }
.jogo-ladrilho.capa-4 { background: var(--capa-luz), var(--capa-4); }
.jogo-ladrilho.capa-5 { background: var(--capa-luz), var(--capa-5); }
.jogo-ladrilho.capa-6 { background: var(--capa-luz), var(--capa-6); }
.jogo-info { min-width: 0; display: flex; flex-direction: column; gap: .1rem; flex: 1 1 auto; }
.jogo-nome {
    font-weight: 600; font-size: .88rem; line-height: 1.25;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.jogo-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* provedor do jogo (PG Soft, Pragmatic Play...) — 05/11/2026. O fornecedor
   (OMG / DreamTech / ao vivo) saiu do cartao e virou o subtitulo do bloco
   (.cas-forn). QUEBRA em vez de cortar: o cartao tem ~150px de texto no
   desktop ("Jogo proprio da DreamTech" nao cabe numa linha). */
.jogo-prov { font-size: .78rem; line-height: 1.3; overflow-wrap: anywhere; }
.jogo-prov strong { font-weight: 650; }
.jogo-prov .muted { white-space: nowrap; }
/* Cassino SEPARADO POR FORNECEDOR (OMG, DreamTech, ao vivo) — 05/11/2026,
   na ficha e no Por produto: nome + contagem, os numeros do fornecedor e a
   grade dele. Do segundo em diante, uma divisoria em cima. */
.cas-forn + .cas-forn { margin-top: 1.3rem; padding-top: 1.1rem; border-top: 1px solid var(--border); }
.cas-forn-cab { display: flex; align-items: baseline; flex-wrap: wrap; gap: .15rem .6rem; margin: 0 0 .5rem; }
.cas-forn-nome { margin: 0; font-size: 1rem; font-weight: 700; }
.cas-forn .prod-resumo { margin: 0 0 .8rem; }
.cas-forn-resto { margin: .6rem 0 0; }
/* a nota que fecha o bloco nao cola na ultima grade */
.cas-forn + p { margin-top: 1rem; }
/* tres numeros em coluna: rotulo a esquerda, valor a direita, alinhado por
   tabular-nums pra comparar cartao com cartao batendo o olho */
.jogo-nums { margin: .35rem 0 0; display: flex; flex-direction: column; gap: .1rem; font-size: .8rem; }
.jogo-nums > div { display: flex; justify-content: space-between; gap: .5rem; }
.jogo-nums dt { color: var(--muted); }
.jogo-nums dd { margin: 0; font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }

/* ---- Catalogo do cassino (/produtos/cassino/jogos) ----
   A mesma arte do lobby dentro da linha da tabela: nome de jogo de cassino nao
   se decora ("20013"), a capa se reconhece na hora. Miniatura menor que a do
   cartao da ficha porque aqui ela divide a celula com o nome e o id, e no
   celular a linha inteira vira cartao. */
.cat-jogo { display: flex; align-items: center; gap: .6rem; min-width: 0; }
/* Bloco "provedor inteiro": o estado por plataforma ANTES do botao. O numero
   que importa e quantos ficam NO AR — e ele que o operador confere depois de
   clicar, entao e ele que aparece grande. */
.prov-estado { display: flex; flex-wrap: wrap; gap: .5rem 1.2rem; margin: .1rem 0 .9rem; }
.prov-chip { display: inline-flex; align-items: center; gap: .4rem; font-size: .85rem; }
.prov-bloco h2 { margin-bottom: .3rem; }
.cat-jogo-txt { display: flex; flex-direction: column; min-width: 0; }
.jogo-thumb.is-mini { width: 38px; height: 50px; border-radius: 6px; }
.jogo-thumb.is-mini .jogo-ladrilho { font-size: 1.2rem; }

/* ---- Barras horizontais (o que ele joga) ----
   A barra so compara; o valor e o percentual vao escritos ao lado, porque
   largura de barra nao se le em numero. */
.bar-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .75rem; }
.bar-head { display: flex; justify-content: space-between; align-items: baseline; gap: .8rem; font-size: .88rem; }
.bar-label { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bar-label small { color: var(--muted); font-weight: 500; font-size: .78em; }
.bar-val { font-variant-numeric: tabular-nums; white-space: nowrap; }
.bar-val small { color: var(--muted); font-weight: 600; }
.bar-track { display: block; height: 8px; border-radius: 99px; background: var(--surface-3); margin: .3rem 0 .25rem; overflow: hidden; }
.bar-fill { display: block; height: 100%; border-radius: 99px; background: var(--chart-in); animation: bar-grow .5s ease-out both; }
/* Fatia que NAO gera comissao (cassino, esportiva). Cinza neutro de proposito:
   nao e "ruim" nem uma segunda serie — e a parte que a conta da comissao nao
   olha. Mesmo cinza do "resto" do grafico de cadastros, que ja significa isso
   na tela de novos jogadores. */
.bar-fill-fora { background: var(--chart-neutral); }
/* Rodape da barra: tres numeros em COLUNA, cada um com o seu rotulo, em vez
   da frase cinza onde o premio tinha o mesmo peso do resto (Bruno, 07/09).
   `auto-fit` com piso de 92px: numa coluna estreita (as quatro visoes da ficha
   do jogador ficam lado a lado) ele quebra para duas linhas sozinho, e como
   todos os itens da lista tem a mesma largura, as colunas caem no mesmo lugar
   em todas as linhas — que e o que deixa a lista ser lida de cima a baixo. */
.bar-foot {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(92px, 1fr));
    gap: .1rem .7rem;
    margin-top: .35rem;
    font-variant-numeric: tabular-nums;
}
.bf { display: flex; flex-direction: column; min-width: 0; }
.bf-rot {
    font-size: .62rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: .05em;
    color: var(--faint);
}
.bf-val { font-size: .82rem; font-weight: 600; white-space: nowrap; }
/* O resultado e a conta que o operador procura: unico em negrito cheio, e
   encostado na direita — assim ele cai embaixo do valor total da linha (que ja
   e alinhado a direita) e as duas leituras verticais ficam na mesma coluna. */
.bf-res { align-items: flex-end; text-align: right; }
.bf-res .bf-val { font-weight: 700; }
/* Os percentuais embaixo do valor (Por produto, 24/09): "79% do total",
   "paga 100,2%", "margem 49,7%". Menores e apagados — o valor continua sendo
   o numero da coluna — e podem quebrar linha: a coluna tem ~100px no celular. */
.bf-pct { font-size: .7rem; font-weight: 500; color: var(--muted); line-height: 1.3; font-variant-numeric: tabular-nums; }
/* Um cartao por item quando a lista tem os percentuais (Por produto e as
   modalidades do bicho): com tres linhas de rodape o nome do item seguinte
   colava no rodape do anterior. O trilho da barra usa a cor da borda: no fundo
   `--surface-2` do cartao o `--surface-3` de sempre quase sumia no escuro. */
.bar-list-cards { gap: .6rem; }
.bar-list-cards > li {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: .75rem .9rem .7rem;
}
.bar-list-cards .bar-track { background: var(--border); }

/* Resumo do produto (/jogos/visao): os mesmos quatro numeros do topo de cada
   bloco, que antes eram uma linha corrida de "434.583 apostas · apostado R$
   ... · premios R$ ..." e quebrava em duas linhas no celular. */
.prod-resumo {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem 1.8rem;
    margin: -.2rem 0 1.1rem;
}
.prod-resumo .bf-val { font-size: 1.05rem; font-weight: 700; letter-spacing: -.01em; }
.prod-resumo .bf-rot { font-size: .64rem; }
/* variante compacta: lista de contagem (de onde vieram os cadastros) */
.bar-list-sm { gap: .5rem; }
.bar-list-sm .bar-head { font-size: .84rem; }
.bar-list-sm .bar-track { height: 6px; margin: .22rem 0 0; }
@keyframes bar-grow { from { transform: scaleX(0); transform-origin: left; } to { transform: scaleX(1); } }
@media (prefers-reduced-motion: reduce) { .bar-fill { animation: none; } }

/* barra so com os chips de tipo (aba Apostas): sem campos, sem botao */
.filter-tipos { padding: .55rem .7rem; }

/* ================= HUB DE PRODUTOS (/produtos) =================
   Cartao de CONTEUDO, nao de numero. Antes reusava `.stat-card` e ficava
   apertado: aquele componente tem calha de 3,6rem a direita (espaco do icone
   do total), altura minima e rodape colado na base — o texto quebrava cedo e
   sobrava um buraco nos produtos "em breve". */
.produtos-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(340px, 100%), 1fr));
    align-items: start;   /* cartao curto nao estica ate a altura do vizinho */
    gap: 1rem;
    margin-bottom: 1.3rem;
}
.produto-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-1);
    padding: 1.1rem 1.2rem;
}
.produto-card.tem-aviso {
    border-color: var(--border-strong);
    box-shadow: var(--shadow-1), inset 3px 0 0 var(--accent);
}
.produto-head {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
    margin-bottom: .35rem;
}
.produto-head h2 {
    margin: 0;
    font-size: .82rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--muted);
}
.produto-head svg { width: 17px; height: 17px; color: var(--muted); flex-shrink: 0; }
.produto-desc { color: var(--muted); font-size: .86rem; line-height: 1.45; margin: 0 0 .9rem; }

/* cada tela do produto e um bloco clicavel com titulo + o que ela responde */
.produto-telas { display: flex; flex-direction: column; gap: .5rem; }
.produto-tela {
    display: block;
    padding: .6rem .75rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-elev);
    text-decoration: none;
    color: inherit;
}
.produto-tela:hover { border-color: var(--accent-line); background: var(--surface-3); }
.produto-tela-topo { display: flex; align-items: center; justify-content: space-between; gap: .6rem; }
.produto-tela-nome { font-weight: 650; font-size: .93rem; }
.produto-tela-desc { display: block; color: var(--muted); font-size: .8rem; line-height: 1.4; margin-top: .15rem; }
.produto-vazio { color: var(--faint); font-size: .84rem; margin: 0; }

/* ---- Liga/desliga de produto por plataforma ----
   O estado tem que ser legivel SEM ler o texto (ponto verde/vermelho) e sem
   depender so de cor (a palavra "no ar"/"suspenso" vai junto). */
.produtos-toggle { display: flex; flex-wrap: wrap; gap: .35rem; }
.produtos-toggle form { margin: 0; }
.produto-btn {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    min-height: 34px;
    padding: .25rem .7rem;
    border-radius: 99px;
    border: 1px solid var(--border-strong);
    background: var(--bg-elev);
    color: var(--text);
    font: 600 .8rem/1 inherit;
    cursor: pointer;
    white-space: nowrap;
}
.produto-btn small { color: var(--muted); font-weight: 600; font-size: .72rem; }
.produto-btn:hover { background: var(--surface-3); }
.produto-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); flex-shrink: 0; }
.produto-btn.is-off { border-color: var(--accent-line); background: var(--accent-soft); }
.produto-btn.is-off .produto-dot { background: var(--red); }
.produto-btn.is-off small { color: var(--accent-fg); }
/* O que o jogador le no card do produto suspenso (migration 042), uma linha
   por produto, embaixo dos botoes. */
.produto-motivo {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .25rem .5rem;
    margin: .5rem 0 0;
    font-size: .84rem;
}
.produto-motivo-nome { color: var(--muted); font-weight: 600; }
.produto-motivo-texto { color: var(--text); overflow-wrap: anywhere; }
.produto-motivo .btn-sm { min-height: 28px; padding: .15rem .6rem; font-size: .78rem; }

/* ================= LOTERIAS: CADASTRO E COTACOES =================
   Duas telas migradas do painel velho (`tsloteria.php` e `painel_config.php`).
   O editor de cotacoes e uma planilha: muitas celulas pequenas, a primeira
   coluna fixa e o estado de cada celula legivel SEM ler o numero (alterada,
   diferente do padrao, zerada = modalidade fechada). */

/* Dias da semana na LISTA: sete quadradinhos, verde = tem sorteio. Legivel de
   relance e sem custo de layout — a alternativa (sete palavras) dobrava a
   largura da linha. */
.dias-semana { display: flex; gap: 2px; }
.dias-semana .dia {
    width: 18px; height: 18px; border-radius: 4px;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: .62rem; font-weight: 800; letter-spacing: 0;
    background: var(--surface-3); color: var(--faint);
}
.dias-semana .dia.on { background: color-mix(in srgb, var(--green) 22%, transparent); color: var(--green); }

/* Dias no FORMULARIO: alvo grande o suficiente para o dedo (o painel e usado
   no celular) — checkbox de 14px com rotulo de 11px nao se acerta andando. */
.dias-escolha { display: flex; flex-wrap: wrap; gap: .5rem; }
.dia-check {
    display: inline-flex; align-items: center; gap: .45rem;
    padding: .5rem .8rem; border: 1px solid var(--border); border-radius: 99px;
    background: var(--surface-2); cursor: pointer; font-size: .88rem; font-weight: 600;
}
.dia-check:has(input:checked) {
    border-color: color-mix(in srgb, var(--green) 45%, var(--border));
    background: color-mix(in srgb, var(--green) 12%, transparent);
}
.dia-check input { accent-color: var(--green); width: 16px; height: 16px; }

/* Formulario da loteria: duas colunas no desktop, uma no celular (mesma regra
   das outras grades — `.field-row` em sequencia desalinha coluna com coluna). */
.form-grid.g-loteria { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }

/* Regioes (nova / completar): nome e origem dividem a linha no desktop e o
   botao fica na BASE dos campos (sem rotulo, ele subiria para a altura do
   label). No celular, uma coluna so, como as outras grades. */
.form-grid.g-regiao { align-items: end; }
@media (min-width: 901px) {
    .form-grid.g-regiao { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; }
}

/* ---- Editor de cotacoes (2a versao) ----
   A 1a foi reprovada por dois motivos, e os dois viraram regra aqui: dava para
   abrir UMA loteria por vez (agora marca-se quantas linhas quiser) e enchia a
   grade de caixa vazia onde a modalidade nem usa o campo (agora e um travessao).
   O resto e planilha: linha baixa, numero alinhado a direita, coluna de
   identificacao parada e o "aplicar" DENTRO da tabela, alinhado as colunas. */

/* Barra de acao: quantas linhas estao marcadas de um lado, o que mudou e o
   botao de salvar do outro. Fica colada no topo do painel. */
.cot-painel { padding-top: .6rem; }
.cot-barra {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
    gap: .5rem 1rem; margin-bottom: .6rem;
}
.cot-barra-info { font-size: .88rem; }
.cot-barra-acoes { display: flex; align-items: center; gap: .8rem; margin-left: auto; }
.cot-tem-mudanca { color: var(--gold); font-weight: 700; }

/* A planilha rola na horizontal COM a coluna da loteria parada: sem isso o
   operador desce 40 linhas e nao sabe mais de qual loteria e a celula. */
.cot-wrap { max-height: 72vh; overflow: auto; }
.cot-tabela { width: 100%; border-collapse: separate; border-spacing: 0; font-size: .84rem; }
.cot-tabela th, .cot-tabela td { padding: .22rem .4rem; border-bottom: 1px solid var(--border); white-space: nowrap; }
.cot-tabela thead th {
    position: sticky; top: 0; z-index: 3;
    background: var(--surface-2); color: var(--muted);
    font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
    text-align: right; border-bottom: 1px solid var(--border-strong);
}
.cot-tabela thead th.cot-fixa { text-align: left; }
/* A 2a linha do cabecalho (o "aplicar") gruda logo abaixo da 1a */
.cot-tabela thead tr.cot-aplicar th { top: 30px; z-index: 3; background: var(--surface-3); border-bottom: 2px solid var(--border-strong); padding: .3rem .4rem; }
.cot-tabela .cot-fixa { position: sticky; left: 0; z-index: 2; background: var(--surface); min-width: 210px; text-align: left; }
.cot-tabela thead .cot-fixa { z-index: 4; }
.cot-tabela tbody tr:nth-child(even) td { background: var(--surface-2); }
.cot-tabela tbody tr:nth-child(even) .cot-fixa { background: var(--surface-2); }
.cot-tabela tbody tr:hover td,
.cot-tabela tbody tr:hover .cot-fixa { background: var(--surface-3); }
.cot-tabela tbody tr.is-marcada td,
.cot-tabela tbody tr.is-marcada .cot-fixa { background: color-mix(in srgb, var(--accent) 10%, transparent); }

/* Marcar linha: o nome da loteria e o proprio alvo do clique */
.cot-check { display: flex; align-items: center; gap: .45rem; cursor: pointer; }
.cot-check input { accent-color: var(--accent); width: 15px; height: 15px; flex-shrink: 0; margin: 0; }
.cot-nome { display: flex; flex-direction: column; line-height: 1.15; font-weight: 600; }
.cot-nome small { color: var(--faint); font-weight: 500; font-size: .7rem; }

/* O "!" nas colunas em que ZERO fecha a modalidade */
.cot-aviso {
    display: inline-flex; align-items: center; justify-content: center;
    width: 13px; height: 13px; margin-left: .2rem; border-radius: 50%;
    background: color-mix(in srgb, var(--red) 20%, transparent); color: var(--red);
    font-size: .58rem; font-weight: 800;
}

.cot-input, .cot-aplicar input {
    width: 84px; padding: .25rem .4rem; font-size: .83rem;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--bg-elev); color: var(--text);
    font-variant-numeric: tabular-nums; text-align: right;
}
.cot-aplicar input { border-style: dashed; border-color: var(--border-strong); }
.cot-input::placeholder, .cot-aplicar input::placeholder { color: var(--faint); }
.cot-input:focus, .cot-aplicar input:focus { outline: 2px solid color-mix(in srgb, var(--accent) 55%, transparent); outline-offset: -1px; }
/* Tres estados, cada um dizendo outra coisa: `is-dif` = tem valor proprio,
   diferente do padrao; `is-alterado` = mexido agora e nao salvo; `is-zero` =
   limite zerado, modalidade FECHADA. */
.cot-input.is-dif { border-color: color-mix(in srgb, var(--chart-in) 45%, var(--border)); }
.cot-input.is-alterado { border-color: var(--gold); background: color-mix(in srgb, var(--gold) 16%, transparent); font-weight: 700; }
.cot-input.is-zero { border-color: var(--red); color: var(--red); font-weight: 700; }

/* Revisao antes de salvar: a lista do que muda, com o que FECHA no topo */
.cot-resumo { max-height: 55vh; overflow: auto; }
.cot-alerta {
    border: 1px solid color-mix(in srgb, var(--red) 40%, var(--border));
    background: color-mix(in srgb, var(--red) 10%, transparent);
    border-radius: var(--radius-sm); padding: .6rem .8rem; margin-bottom: .8rem; font-size: .88rem;
}
.cot-alerta ul { margin: .3rem 0 0 1rem; }
.cot-diff { width: 100%; border-collapse: collapse; font-size: .85rem; }
.cot-diff th, .cot-diff td { border-bottom: 1px solid var(--border); padding: .3rem .5rem; text-align: left; }
.cot-diff .de { color: var(--muted); text-decoration: line-through; }
.cot-diff .para { color: var(--green); font-weight: 700; }
.cot-diff tr.fecha .para { color: var(--red); }

@media (max-width: 900px) {
    /* A planilha NAO vira cartao (unica tabela do painel que escapa da regra):
       numero empilhado em cartao perde a comparacao entre linhas, que e a razao
       da tela. Ela rola na horizontal, com a coluna da loteria fixa. */
    .cot-wrap { max-height: 68vh; }
    .cot-tabela .cot-fixa { min-width: 150px; }
    .cot-tabela .cot-fixa,
    .cot-tabela .cot-fixa .cot-nome { text-align: left; }
    .cot-input, .cot-aplicar input { width: 72px; }
    .cot-barra-acoes { width: 100%; justify-content: space-between; margin-left: 0; }
}

/* ================= VISAO DO JOGADOR =================
   As abas Apostas e Transacoes da ficha sao a MESMA tela que o jogador ve no
   app ("Apostas & Transacoes" do stars-client, files-v3/resultados.html):
   mesma marcacao, mesmas classes, mesmo layout. Pedido do Bruno (04/08) —
   quando o jogador reclama, o atendimento tem que estar olhando a tela dele,
   nao uma traducao dela.
   O CSS foi copiado de la; a unica troca e a ponte de tokens abaixo, que liga
   as variaveis do app as do painel para o bloco viver nos DOIS temas (o app e
   so escuro). Ao mexer, comparar com o original antes de "melhorar". */
.cliente-view {
    --color-surface: var(--surface);
    --c-surface-2: var(--surface-2);
    --c-border: var(--border);
    --color-text: var(--text);
    --c-text-soft: var(--muted);
    --c-text-muted: var(--faint);
    --c-primary-soft: var(--accent-soft);
    --c-accent: var(--accent-fg);
    --font-sans: inherit;
}

.apostas-list { display: flex; flex-direction: column; gap: 14px; }

.cliente-view .sorteio {
    background: var(--color-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    overflow: hidden;
}
.cliente-view .sorteio-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 14px 16px;
    border-bottom: 1px solid var(--c-border);
    background: var(--c-surface-2);
}
.cliente-view .sorteio-head .name { font-size: 14px; font-weight: 700; }
.cliente-view .sorteio-head .badge {
    font-size: 10px; font-weight: 700;
    padding: 3px 9px; border-radius: 999px;
    text-transform: uppercase; letter-spacing: .04em;
    background: color-mix(in srgb, var(--green) 16%, transparent); color: var(--green);
}

/* ---- Segmentado "Por loteria | Por pule" (igual ao app) ---- */
.seg {
    display: flex; gap: 3px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 11px;
    padding: 3px;
    margin-bottom: 1rem;
}
.seg a {
    flex: 1; min-width: 0;
    display: flex; align-items: center; justify-content: center; gap: 5px;
    padding: 8px 6px;
    border-radius: 8px;
    text-align: center;
    text-decoration: none;
    font-size: 12px; font-weight: 600;
    color: var(--muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* o "..." mora no ROTULO, nao no link: assim a aba encurta o texto ("Aniversa...")
   e a bolinha continua inteira — ela e o dado que fez a aba valer o olhar */
.seg .seg-lbl { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.seg a:hover { color: var(--text); }
.seg a.active { background: var(--accent-soft); color: var(--accent-fg); font-weight: 700; }

/* Bolinha de contagem da aba (depositos/saques pendentes, cadastros e
   aniversariantes de hoje). Some quando e zero: aba sem pendencia nao tem
   nada a dizer, e um "0" em toda aba viraria ruido de fundo. Na aba ATIVA ela
   inverte (fundo cheio), porque ali o fundo ja e o accent-soft e a bolinha
   sumiria dentro dele. */
.seg-count {
    flex: 0 0 auto;
    min-width: 17px;
    padding: 0 5px;
    border-radius: 9px;
    background: var(--accent-soft);
    color: var(--accent-fg);
    border: 1px solid var(--accent-line);
    font-size: 10.5px; font-weight: 700; line-height: 15px;
    font-variant-numeric: tabular-nums;
}
.seg a.active .seg-count {
    background: var(--accent);
    color: var(--accent-ink);
    border-color: var(--accent);
}
/* sub-navegacao da area (Ranking | Novos cadastros): o mesmo segmentado, mas
   sem esticar de ponta a ponta no desktop — vira um par de abas */
/* 140px por aba, com piso de 3 (= os 420px de sempre para areas de 2 e 3
   abas). Com 4 abas, 420px cortava os rotulos no desktop ("Novos cadas...",
   "Aniversarian...") com tela sobrando. `--abas` vem do Areas::nav. */
.seg-inline { max-width: calc(max(3, var(--abas, 3)) * 140px); }
/* Area com 5 abas ou mais no celular (Jogadores ganhou a sexta, Afiliados, em
   29/10): numa linha so cada aba ficava com ~57px a 390 e ate "Ranking" virava
   "Ranki...". Quebra em linhas de 3, como as abas da ficha (`.tabs`). */
@media (max-width: 640px) {
    .seg-muitas { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ============================================================
   ATALHOS (sql/029) — a barra que cada admin monta para si
   ------------------------------------------------------------
   Fica no topo de TODA tela, antes do titulo, porque e navegacao
   e nao conteudo. Ela e propositalmente mais discreta que o
   segmentado de abas: o `.seg` diz onde voce esta DENTRO da
   area, a barra de atalhos diz para onde pular. Se as duas
   tivessem o mesmo peso, a tela passaria a ter dois comandos
   competindo acima do titulo.

   No celular ela rola de lado em vez de quebrar em duas linhas:
   com quebra, o titulo da pagina descia para fora da primeira
   dobra justamente nas telas de trabalho.

   GRUDADA NO TOPO (pedido do Bruno, 10/09): atalho serve para
   pular de tela, e a hora de pular chega no meio do relatorio —
   ate aqui era preciso rolar tudo de volta para alcanca-lo. No
   celular ela para debaixo da topbar (`top: var(--topbar-h)`),
   nunca por cima dela.

   Tres detalhes que ela precisa para funcionar grudada:
   1. FUNDO E SANGRIA ate a borda do `.main`. Sem os dois, o
      conteudo passa por baixo aparecendo nas calhas laterais.
      Os numeros negativos aqui sao os do `padding` do `.main` —
      mexeu la, mexe aqui (2rem no desktop, .9rem no celular).
   2. `margin-top` negativo compensando o `padding-top` novo: em
      repouso a barra tem que ficar onde sempre esteve, senao
      grudar custaria meio centimetro em toda tela.
   3. `.is-stuck` (posto pelo `admin.js`) so quando ela esta de
      fato grudada — a linha e a sombra separam a barra do
      conteudo que passa por baixo, e em repouso nao existe
      moldura nenhuma, que e como ela foi desenhada.
   ============================================================ */
.atalhos {
    position: sticky;
    top: 0;                      /* no celular desce para debaixo da topbar */
    z-index: 30;                 /* abaixo da topbar (40) e do scrim (45) */
    display: flex;
    align-items: center;
    gap: .3rem;
    margin: -.7rem -2rem 1rem;
    padding: .5rem 2rem .45rem;
    background: var(--bg);
    overflow-x: auto;
    scrollbar-width: none;
}
.atalhos::-webkit-scrollbar { display: none; }
/* DESKTOP QUEBRA LINHA (05/10, teto de 8 -> 15): rolando de lado com a barra
   de rolagem escondida, a 1400px os ultimos atalhos — e o "+ Atalhos", que e
   o unico jeito de editar a barra — ficavam fora da tela, e com mouse nao ha
   como alcanca-los. Duas linhas custam ~38px a mais so para quem montou muitos.
   O celular continua rolando de lado (ver o comentario acima). */
@media (min-width: 901px) {
    .atalhos { flex-wrap: wrap; overflow-x: visible; }
}
.atalhos.is-stuck {
    border-bottom: 1px solid var(--border-strong);
    box-shadow: var(--shadow-1);
}
/* Sem atalho montado sobra so o convite: grudar uma barra que nao
   leva a lugar nenhum seria cobrar espaco de tela por nada. */
.atalhos-vazia { position: static; }
.atalho {
    flex: 0 0 auto;
    display: inline-flex; align-items: center; gap: 5px;
    padding: 5px 10px;
    border: 1px solid var(--border);
    border-radius: 99px;
    background: var(--surface);
    color: var(--muted);
    font-size: 12px; font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    min-height: 30px;
}
.atalho:hover { color: var(--text); border-color: var(--border-strong); }
.atalho.active {
    background: var(--accent-soft);
    border-color: var(--accent-line);
    color: var(--accent-fg);
}
/* o lapis nao compete com os atalhos: sem borda ate o hover */
.atalho-add { border-color: transparent; color: var(--faint); }
.atalho-add:hover { border-color: var(--border); }
.atalho .seg-count { line-height: 15px; }

/* ---- Tela /atalhos: montar a barra ---- */
.atalho-lista { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .4rem; }
.atalho-item {
    display: flex; align-items: center; gap: .6rem;
    padding: .5rem .65rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.atalho-item.is-on { opacity: .6; }
.atalho-nome { flex: 1 1 auto; min-width: 0; }
.atalho-titulo { display: block; font-weight: 650; font-size: .9rem; }
.atalho-area { display: block; font-size: .72rem; }
.atalho-acoes { flex: 0 0 auto; display: flex; align-items: center; gap: .25rem; }
.atalho-acoes .icon-btn { width: 30px; height: 30px; }
.atalho-acoes .icon-btn[disabled] { opacity: .35; cursor: default; }
.atalho-tirar:hover { color: var(--err-text); }
/* `display: flex` numa classe VENCE o `display: none` que o navegador da ao
   [hidden] (regra de UA): sem esta linha o botao de salvar aparecia sempre,
   inclusive antes de arrastar coisa nenhuma. */
.atalho-salvar { display: flex; align-items: center; gap: .6rem; margin-top: .8rem; }
.atalho-salvar[hidden] { display: none; }

/* A alca so aparece como alca quando o JS ligou o arrastar — sem ele, arrastar
   nao faz nada e um cursor de "pegue aqui" seria mentira. */
.atalho-alca { flex: 0 0 auto; color: var(--faint); font-size: 1rem; line-height: 1; }
.js-arrasta .atalho-alca { cursor: grab; touch-action: none; }
.js-arrasta .atalho-item.arrastando {
    cursor: grabbing;
    opacity: .9;
    border-color: var(--accent-line);
    box-shadow: 0 6px 18px rgba(0, 0, 0, .18);
}
.js-arrasta .atalho-item.alvo { border-style: dashed; border-color: var(--accent-line); }

/* ============================================================
   FINANCEIRO — plano de contas em arvore (/financeiro)
   ------------------------------------------------------------
   O codigo E a hierarquia ('03' e o grupo, '03.47' a conta), e o
   legado desenhava isso com `padding-left` calculado no PHP a
   cada linha. Aqui o nivel vem numa variavel (`--n`) e o recuo e
   do CSS: no celular, onde a tabela vira cartao, ele nao vale —
   um cartao recuado 40px so perde largura.
   ============================================================ */
/* O recuo por nivel e o que separa o grupo das contas dele — 14px nao dava
   para ver (Bruno, 08/09: "nao ta dando o espacamento pra indicar a area do
   01"). 26px por nivel, e a linha do GRUPO ganha faixa propria: e ela que diz
   onde uma area comeca, do jeito que o legado fazia com o negrito preto contra
   o cinza das contas. */
/* `.tabela-densa td` fixa `padding-inline: .5rem` e vence `.cc-cod` por
   especificidade (classe+elemento contra classe) — por isso o recuo nao saia
   do lugar. Com o `td` no seletor, o recuo soma ao padding da tabela. */
.table-cards td.cc-cod,
.table-cards td.cc-nome { padding-left: calc(.5rem + var(--n, 0) * 26px); }
.cc-raiz .cc-cod, .cc-raiz .cc-nome { font-weight: 700; }
.cc-raiz > td {
    background: var(--surface-2);
    border-top: 1px solid var(--border-strong);
}
.cc-raiz .cel-sub { font-weight: 400; }

/* Previsao de entrada (colunas "ainda vai cair na conta") — o legado marcava
   com fundo salmao; aqui e um tom da propria superficie, para o tema escuro
   nao herdar cor de papel. Elas nao sao saldo: sao promessa. */
.col-prev { background: var(--surface-2); }
thead .col-prev { color: var(--gold); }

/* Lancamento dentro da conta: recuado mais um degrau, em corpo de apoio — ele
   e o COMPROVANTE da linha de cima, nao um centro de custo a mais. */
.cc-lanc > td { background: var(--surface); font-size: .84rem; }
.cc-lanc .cel-main { font-weight: 600; }

/* A regua da area: um fio vertical na altura do recuo, ligando as contas ao
   grupo. Sem ele, 26px de vazio sao so vazio; com ele, a coluna mostra ate
   onde a area do 01 vai. */
.cc-cod { position: relative; }
tr:not(.cc-raiz) > .cc-cod::before {
    content: "";
    position: absolute;
    /* no MEIO do recuo do proprio nivel: padding da tabela + os niveis
       anteriores + metade do degrau */
    left: calc(.5rem + (var(--n, 1) - 1) * 26px + 12px);
    top: 0;
    bottom: 0;
    width: 1px;
    background: var(--border-strong);
}

/* A opcao "listar os lancamentos" do cadastro: caixa + explicacao, porque a
   escolha so faz sentido com o porque do lado (conta de volume automatico). */
.cc-check {
    display: flex; align-items: flex-start; gap: .6rem;
    margin: .2rem 0 1rem;
    padding: .7rem .8rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    cursor: pointer;
}
.cc-check input { margin-top: .15rem; flex: 0 0 auto; }

.cc-check strong { display: block; font-size: .9rem; }
.cc-check small { display: block; margin-top: .15rem; line-height: 1.45; }

@media (max-width: 900px) {
    /* no cartao o recuo nao vale (cada linha ja e um bloco) e a regua nao tem
       coluna onde morar — os seletores repetem `.table-cards td` porque e com
       essa especificidade que o recuo do desktop foi escrito */
    .table-cards td.cc-cod,
    .table-cards td.cc-nome { padding-left: 0; }
    .table-cards tr:not(.cc-raiz) > td.cc-cod::before { display: none; }
    .cc-raiz > td { background: transparent; }
}

/* ---- Resultado do sorteio dentro do card (JB) ---- */
.draw-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.draw-table thead th {
    font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
    color: var(--c-text-muted); text-align: left;
    padding: 8px 14px; border-bottom: 1px solid var(--c-border);
}
.draw-table thead th:nth-child(2), .draw-table thead th:nth-child(3) { text-align: center; }
.draw-table tbody td { padding: 8px 14px; border-bottom: 1px solid var(--c-border); vertical-align: middle; }
.draw-table tbody tr:last-child td { border-bottom: 0; }
.draw-table tbody tr.first td { background: var(--c-primary-soft); }
.draw-table .dt-pos { font-weight: 800; color: var(--c-text-muted); width: 54px; }
.draw-table tr.first .dt-pos { color: var(--c-accent); }
.draw-table .dt-num { font-weight: 800; letter-spacing: .04em; text-align: center; font-variant-numeric: tabular-nums; }
.draw-table .dt-grp { text-align: center; font-weight: 700; color: var(--c-text-soft); }
.draw-table .dt-b { font-weight: 600; color: var(--color-text); }
.draw-table .dt-bicho { display: inline-flex; align-items: center; gap: 8px; }
.draw-table .dt-bicho img {
    width: 28px; height: 28px; border-radius: 50%; object-fit: cover;
    background: var(--color-surface); border: 1px solid var(--c-border); flex-shrink: 0;
}
.draw-table .dt-bicho.first b { color: var(--c-accent); font-weight: 800; }

/* dezenas de SEN/QUI/LOT — bolinha por dezena, cor por loteria (como no app) */
.sorteio-results.lottery { display: flex; flex-wrap: wrap; gap: 5px; padding: 12px 14px; }
.sorteio-results.lottery .ball {
    width: 28px; height: 28px;
    display: grid; place-items: center;
    border-radius: 50%;
    font-size: 11px; font-weight: 800;
    color: #fff; flex-shrink: 0;
}
.sorteio-results.lottery .ball.sen { background: #4caf50; }
.sorteio-results.lottery .ball.qui { background: #9c27b0; }
.sorteio-results.lottery .ball.lot { background: #d4a017; color: #1a1305; }

.sorteio-head .badge.gray { background: var(--surface-3); color: var(--c-text-muted); }
.sorteio-head .quando { font-size: 11.5px; color: var(--c-text-muted); font-weight: 600; }

/* ---- Card de pule ---- */
.pule-card .pule-head { justify-content: space-between; gap: 10px; cursor: pointer; user-select: none; }
.pule-head-info { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-width: 0; }
.pule-head-info .name { white-space: nowrap; }
.pule-head-meta { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.pule-head-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.pule-card .pule-head .pule-time { font-size: 11.5px; color: var(--c-text-muted); font-weight: 600; }
.pule-caret { flex-shrink: 0; color: var(--c-text-muted); transition: transform .2s; }
.pule-collapsible.collapsed .pule-caret { transform: rotate(-90deg); }
.pule-collapsible.collapsed .pule-body { display: none; }

.pule-lot { border-top: 1px solid var(--c-border); }
.pule-lot:first-child { border-top: 0; }
.pule-lot-head { display: flex; align-items: center; gap: 8px; padding: 9px 14px 5px; }
.pule-lot-nome { font: 800 12px var(--font-sans); color: var(--c-accent); text-transform: uppercase; letter-spacing: .03em; }
.pule-lot-qtd { font: 600 10.5px var(--font-sans); color: var(--c-text-muted); }
.pule-foot {
    display: flex; justify-content: space-between; align-items: center;
    gap: 10px; flex-wrap: wrap;
    padding: 11px 14px;
    border-top: 1px solid var(--c-border);
    background: var(--c-surface-2);
    font-size: 12.5px; color: var(--c-text-soft);
}
.pule-foot b { color: var(--color-text); font-weight: 800; }
.pule-foot .pf-vals { display: flex; gap: 14px; flex-wrap: wrap; align-items: center; }
.pule-foot .pule-premio b { color: var(--c-accent); }

/* ---- Linha de aposta (sem o checkbox/olhinho do app: aqui nao ha acao) ---- */
.aposta {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 8px; align-items: center;
    padding: 8px 12px;
    border-top: 1px solid var(--c-border);
}
.aposta:first-child { border-top: 0; }
.aposta:hover { background: var(--c-surface-2); }
.aposta .info { min-width: 0; }
.aposta .info .top { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.aposta .info .apt-id { font-size: 10.5px; font-weight: 700; color: var(--c-text-muted); }
.aposta .info .sigla {
    font-size: 10px; font-weight: 800;
    padding: 1px 6px;
    background: var(--c-primary-soft); color: var(--c-accent);
    border-radius: 6px;
    text-transform: uppercase; letter-spacing: .04em;
}
.aposta .info .nums {
    min-width: 0;
    font-size: 13px; font-weight: 800; color: var(--color-text);
    letter-spacing: .01em; word-break: break-word; overflow-wrap: anywhere;
}
.aposta .info .sub { display: block; font-size: 10.5px; color: var(--c-text-muted); margin-top: 2px; }
.aposta .right { text-align: right; align-self: center; }
.aposta .right .v { display: block; font-size: 13px; font-weight: 800; color: var(--color-text); }
.aposta .right .premio { display: block; font-size: 11px; color: var(--c-accent); font-weight: 700; margin-top: 3px; }

/* ---- Item de transacao ---- */
.tr-list { display: flex; flex-direction: column; }
.tr-item {
    display: flex; align-items: flex-start; gap: 14px;
    padding: 13px 14px;
    margin-top: 6px;
    background: var(--color-surface);
    border: 1px solid var(--c-border);
    border-radius: 10px;
}
.tr-item:first-child { margin-top: 0; }
.tr-item .info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.tr-item .info .d { font-size: 13.5px; font-weight: 700; color: var(--color-text); line-height: 1.2; }
.tr-item .info .id { font-size: 11.5px; color: var(--c-text-muted); font-weight: 500; line-height: 1.3; }
/* bonus que venceu: a frase que o jogador le no app (26/10) */
.tr-item .info .mot { font-size: 12px; color: var(--text); font-weight: 500; line-height: 1.35; white-space: normal; }
.tr-item .right { display: flex; flex-direction: column; align-items: flex-end; gap: 5px; flex-shrink: 0; text-align: right; }
.tr-item .right .v { font-size: 14px; font-weight: 800; white-space: nowrap; line-height: 1; }
.tr-item .v.pos { color: var(--green); }
.tr-item .v.neg { color: var(--red); }
.tr-item .saldo { font-size: 11px; color: var(--c-text-muted); font-weight: 600; white-space: nowrap; }

/* Pilulas de status: no app sao hex fixos com override de tema; aqui saem dos
   tokens do painel, que ja viram sozinhos no claro/escuro */
.cliente-view .st {
    display: inline-block;
    font-size: 9.5px; font-weight: 700;
    padding: 3px 9px; border-radius: 999px;
    text-transform: uppercase; letter-spacing: .04em;
    background: var(--surface-3); color: var(--c-text-muted);
}
.aposta .right .st { margin-top: 3px; padding: 2px 6px; }
.cliente-view .st.ok, .cliente-view .st.win { background: color-mix(in srgb, var(--green) 16%, transparent); color: var(--green); }
.cliente-view .st.warn, .cliente-view .st.wait { background: color-mix(in srgb, var(--gold) 18%, transparent); color: var(--gold); }
.cliente-view .st.err, .cliente-view .st.rev { background: color-mix(in srgb, var(--red) 16%, transparent); color: var(--red); }

/* ---- extrato no formato do app: resumo de saldo + secoes por tipo ----
   O app (files-v3/resultados.html) usa JS + grid-animation; aqui e <details>,
   que colapsa sem JavaScript nenhum. As cores saem dos tokens do painel, nunca
   do hex do app — senao a tela some no tema claro. */
.cliente-view .tr-summary {
    display: grid; grid-template-columns: 1fr 1fr; gap: .6rem;
    margin-bottom: .8rem;
}
.cliente-view .tr-summary .b {
    display: flex; flex-direction: column; gap: 2px;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); padding: .7rem .9rem;
}
.cliente-view .tr-summary .lab { font-size: .78rem; color: var(--muted); font-weight: 600; }
.cliente-view .tr-summary .v { font-size: 1.15rem; font-weight: 800; }
.cliente-view .tr-summary .quando { font-size: .72rem; color: var(--muted); }

.cliente-view .tr-secoes { display: flex; flex-direction: column; gap: .5rem; }
.cliente-view .tr-section {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); overflow: hidden;
}
.cliente-view .tr-section[open] { border-color: var(--border-strong); }
.cliente-view .tr-head {
    display: flex; align-items: center; gap: .7rem;
    padding: .75rem .9rem; cursor: pointer; user-select: none;
    list-style: none;
}
.cliente-view .tr-head::-webkit-details-marker { display: none; }
.cliente-view .tr-head .ico {
    width: 34px; height: 34px; flex-shrink: 0;
    display: grid; place-items: center; border-radius: 10px;
}
.cliente-view .tr-head .ico svg { width: 17px; height: 17px; }
.cliente-view .tr-head .ico.deposito,
.cliente-view .tr-head .ico.premio { background: color-mix(in srgb, var(--green) 14%, transparent); color: var(--green); }
.cliente-view .tr-head .ico.saque  { background: color-mix(in srgb, var(--red) 14%, transparent); color: var(--red); }
.cliente-view .tr-head .ico.bonus  { background: color-mix(in srgb, var(--gold) 16%, transparent); color: var(--gold); }
.cliente-view .tr-head .ico.expirado { background: color-mix(in srgb, var(--red) 10%, transparent); color: var(--gold); }
.cliente-view .tr-head .ico.apostas,
.cliente-view .tr-head .ico.carteira { background: var(--surface-3); color: var(--text); }
.cliente-view .tr-head .t { flex: 1; min-width: 0; }
.cliente-view .tr-head .t .name { display: block; font-size: .92rem; font-weight: 700; }
.cliente-view .tr-head .t .sub { display: block; font-size: .72rem; color: var(--muted); margin-top: 1px; }
.cliente-view .tr-head .v { font-size: .98rem; font-weight: 800; white-space: nowrap; }
.cliente-view .tr-head .v.pos { color: var(--green); }
.cliente-view .tr-head .v.neg { color: var(--red); }
.cliente-view .tr-head .chev { width: 18px; height: 18px; opacity: .5; flex-shrink: 0; transition: transform .2s; }
.cliente-view .tr-head .chev svg { width: 18px; height: 18px; display: block; }
.cliente-view .tr-section[open] .tr-head .chev { transform: rotate(180deg); }
.cliente-view .tr-inner { padding: .1rem .55rem .6rem; }
.cliente-view .tr-mais { margin: .5rem .3rem 0; }

/* resultado dentro da pule: mesma tabela da visao por loteria, mais discreta
   (ela aparece uma vez por divisao, entao nao pode competir com as apostas) */
.cliente-view .draw-compacta { margin: .2rem 0 .45rem; font-size: .82rem; }
.cliente-view .draw-compacta td { padding: .18rem .35rem; }
.cliente-view .pule-lot-res { margin: .2rem 0 .45rem; }

/* drill-down do extrato: grupo de sorteio -> loteria -> lancamentos
   (mesma hierarquia do app, feita com <details> aninhado, sem JS de colapso) */
.cliente-view .tr-sub-wrap { border-top: 1px solid var(--border); }
.cliente-view .tr-sub-wrap:first-child { border-top: 0; }
.cliente-view .tr-sub {
    display: flex; align-items: center; gap: .6rem;
    padding: .55rem .5rem; cursor: pointer; user-select: none; list-style: none;
}
.cliente-view .tr-sub::-webkit-details-marker { display: none; }
.cliente-view .tr-sub:hover { background: var(--surface-2); }
.cliente-view .tr-sub .nm { flex: 1; min-width: 0; font-size: .86rem; font-weight: 650; }
.cliente-view .tr-sub .qt { font-size: .72rem; }
.cliente-view .tr-sub .v { font-size: .88rem; font-weight: 750; white-space: nowrap; }
.cliente-view .tr-sub .v.pos { color: var(--green); }
.cliente-view .tr-sub .v.neg { color: var(--red); }
.cliente-view .tr-sub .chev { width: 15px; height: 15px; opacity: .45; flex-shrink: 0; transition: transform .2s; }
.cliente-view .tr-sub .chev svg { width: 15px; height: 15px; display: block; }
.cliente-view .tr-sub-wrap[open] > .tr-sub .chev { transform: rotate(180deg); }
.cliente-view .tr-sub.nivel2 { padding-left: 1.1rem; }
.cliente-view .tr-sub.nivel2 .nm { font-weight: 550; color: var(--muted); }
.cliente-view .tr-sub-inner { padding-left: .5rem; }

/* olhinho da linha (mesmo papel do `.pule-eye` do app) + detalhe no modal */
.cliente-view .tr-eye {
    flex-shrink: 0; width: 30px; height: 30px; margin-left: .4rem;
    display: grid; place-items: center;
    background: transparent; border: 1px solid var(--border); border-radius: 9px;
    color: var(--muted); cursor: pointer;
    transition: border-color .15s, color .15s, background .15s;
}
.cliente-view .tr-eye svg { width: 16px; height: 16px; }
.cliente-view .tr-eye:hover { border-color: var(--accent-line); color: var(--accent-fg); background: var(--accent-soft); }
.cliente-view .tr-item { align-items: center; }

.detail-rows { display: flex; flex-direction: column; gap: 1px; }
.detail-rows .dt-row {
    display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
    padding: .45rem .1rem; border-bottom: 1px solid var(--border);
}
.detail-rows .dt-row:last-child { border-bottom: 0; }
.detail-rows .dt-row .k { font-size: .82rem; color: var(--muted); font-weight: 600; }
.detail-rows .dt-row .v { font-size: .9rem; font-weight: 700; text-align: right; word-break: break-word; }
.detail-rows .dt-row .v.pos { color: var(--green); }
.detail-rows .dt-row .v.neg { color: var(--red); }
.dt-motivo { margin: .7rem 0 0; padding: .6rem .75rem; border-radius: var(--radius-sm); font-size: .88rem; line-height: 1.45;
    background: color-mix(in srgb, var(--gold) 12%, transparent); }
.detail-rows .dt-row .v.gold { color: var(--gold); }
.detail-rows .dt-titulo { font-size: .85rem; font-weight: 700; margin: .9rem 0 .1rem; color: var(--muted); }
.detail-rows .draw-table { width: 100%; margin-top: .2rem; }

@media (max-width: 560px) {
    .cliente-view .tr-summary { grid-template-columns: 1fr; }
}

.cliente-view .vazio { padding: 18px 14px; font-size: 13px; color: var(--c-text-muted); text-align: center; }

@media (max-width: 420px) {
    .tr-item { padding: 12px; gap: 10px; }
    .tr-item .info .d { font-size: 13px; }
    .tr-item .right .v { font-size: 13.5px; }
    .cliente-view .st { font-size: 9px; padding: 2px 7px; }
}

/* ---- Pule (lista "Minhas apostas") ---- */
.pule {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    margin-bottom: .7rem;
    background: var(--surface-2);
}
.pule > summary {
    cursor: pointer;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .3rem .9rem;
    padding: .65rem .9rem;
    font-size: .9rem;
}
.pule > summary::-webkit-details-marker { display: none; }
.pule > summary::marker { content: ''; }
.pule > summary::before {
    content: '\25B8';
    color: var(--faint);
    transition: transform .15s ease;
}
.pule[open] > summary::before { transform: rotate(90deg); }
.pule-id { font-weight: 700; }
.pule-meta { font-size: .8rem; }
.pule-vals { margin-left: auto; font-variant-numeric: tabular-nums; white-space: nowrap; display: flex; gap: .6rem; }
.pule-valor { font-weight: 650; }
.pule .table-wrap { border-top: 1px solid var(--border); background: var(--surface); }
.pule-foot { padding: .55rem .9rem; margin: 0; border-top: 1px solid var(--border); }

/* A APOSTA da linha: modalidade (cel-main), colocacao e numero jogado. Os
   dois ultimos sao o que se confere contra o resultado do sorteio, entao nao
   podem ter o corpo de nota de rodape que o `.cel-sub` da a todo o resto da
   tabela (Bruno, 07/09). O numero e o dado principal: fica no maior corpo da
   celula, em negrito e com um respiro entre os digitos, porque "02,01,13" se
   le digito a digito. */
.jogo-aposta { display: block; margin-top: .1rem; }
/* No desktop a coluna "Aposta" e estreita (a tabela tem oito): colocacao e
   numero ficam em linhas proprias, sem separador. Com os dois na mesma linha,
   o "·" sobrava pendurado no fim ("1 ao 5 ·" / "618"). No cartao do celular,
   onde a linha e a largura da tela, eles voltam a caber lado a lado. */
.ja-coloc { display: block; color: var(--muted); font-weight: 600; }
.ja-num { display: block; }
.ja-num {
    font-size: .95rem; font-weight: 700;
    letter-spacing: .04em;
    color: var(--text);
}
/* id de rodada do cassino/bingo: continua sendo o campo `numeros`, mas nao e
   palpite — volta ao corpo de apoio e pode quebrar onde couber */
.ja-num.is-id {
    font-size: .74rem; font-weight: 600;
    letter-spacing: 0;
    color: var(--muted);
    overflow-wrap: anywhere;
}

/* Resultado do sorteio: sai SEMPRE inteiro — quebra em mais linhas quando
   nao couber, mas nunca corta numero (uma dezena escondida obrigaria a
   conferir o resultado em outro lugar) */
.cel-resultado { white-space: normal; font-size: .82rem; min-width: 13rem; }

/* Premios numerados (1o ao 7o) com grupo/bicho. Duas colunas para os sete
   premios nao empurrarem a linha da tabela para sete alturas. */
.premios {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(2, auto);
    gap: .05rem .9rem;
    justify-content: start;
}
.premios li { display: flex; align-items: baseline; gap: .35rem; line-height: 1.5; white-space: nowrap; }
.premio-pos { color: var(--faint); font-size: .72rem; min-width: 1.2rem; text-align: right; }
/* Largura fixa no numero (cabe a milhar) com o texto a direita: o 7o premio da
   federal tem tres digitos e, sem isso, a coluna inteira desanda uma casa. */
.premio-num { font-weight: 600; font-variant-numeric: tabular-nums; min-width: 2.5rem; text-align: right; }
.premio-grupo { color: var(--muted); font-size: .74rem; }

/* ---- Coluna "Valor / Premio" da listagem de jogos ----
   Tres numeros com nomes parecidos (apostado, possivel, pago) empilhados: sem
   rotulo em cada um, so a cor dizia qual era qual. O rotulo e minusculo de
   proposito — quem le a coluna quer o numero, o rotulo so desempata. */
/* NAO por `display: flex` no proprio <td> (Bruno, 08/09: "ta quebrado aqui,
   essas linhas"). O td deixa de ser celula de tabela, o navegador o embrulha
   numa celula anonima e o `border-bottom` passa a acompanhar o bloco flex, nao
   a linha — a divisoria aparece curta e na altura errada, exatamente o defeito
   que a nota da coluna de acao ja descreve no CLAUDE.md. Aqui a celula
   continua celula: quem empilha sao os proprios itens, cada um um bloco flex
   alinhado a direita. */
.cel-valores { text-align: right; }
.v-item { display: flex; align-items: baseline; justify-content: flex-end; gap: .35rem; }
.v-rot { color: var(--faint); font-size: .66rem; text-transform: uppercase; letter-spacing: .04em; }
.v-num { font-weight: 600; font-variant-numeric: tabular-nums; }
.v-ganho .v-num { color: var(--green); }

/* Texto longo (id de rodada do cassino): curto no desktop com o valor inteiro
   no title; no celular nao ha hover, entao o cartao mostra tudo */
.trunc { cursor: help; }
.trunc-full { display: none; }

/* ---- Paginacao ---- */
.pager {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .8rem;
    margin-top: 1rem;
    padding-top: .9rem;
    border-top: 1px solid var(--border);
}
.pager .is-off { opacity: .4; pointer-events: none; }

/* ---- Matriz de permissoes ---- */
.matrix th, .matrix td { white-space: nowrap; }
.matrix th:first-child, .matrix td:first-child {
    position: sticky;
    left: 0;
    z-index: 1;
    background: var(--surface);
    white-space: normal;
}
.matrix tbody tr:hover td:first-child { background: var(--surface-2); }
.matrix .matrix-modulo td {
    background: var(--surface-2);
    color: var(--accent-fg);
    font-weight: 700;
    font-size: .78rem;
    text-transform: uppercase;
    letter-spacing: .05em;
}
.matrix input[type="checkbox"] { width: 18px; height: 18px; }
.matrix td .mono { display: block; color: var(--faint); }
/* padding-right maior: a seta do select e desenhada no fundo */
.select-sm { padding: .3rem 1.9rem .3rem .6rem; min-height: 34px; font-size: .84rem; width: auto; }
.scroll-hint { display: none; }

/* ---- Vazio / erro ---- */
.empty-state { text-align: center; padding: 4rem 1rem; }
.empty-icon { font-size: 2.6rem; margin-bottom: .8rem; }
.empty-state .btn { margin-top: 1rem; }

.danger-zone {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-top: 1.4rem;
    padding-top: 1.1rem;
    border-top: 1px solid var(--border);
}
.danger-zone p { margin: .2rem 0 0; max-width: 52ch; }
.danger-zone form { margin: 0; }

.user-head { margin-bottom: 1.2rem; padding-bottom: 1rem; border-bottom: 1px solid var(--border); }
.user-head h2 { margin-bottom: .2rem; }
.user-head p { margin: 0; font-size: .88rem; }

/* ================= MOBILE ================= */
@media (max-width: 900px) {
    body { font-size: 15.5px; }

    .topbar { display: flex; }
    .shell { min-height: calc(100dvh - var(--topbar-h)); }

    /* Sidebar vira gaveta lateral */
    .sidebar {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        height: 100dvh;
        width: min(84vw, 300px);
        z-index: 50;
        box-shadow: var(--shadow-3);
        transform: translateX(-102%);
        transition: transform .24s ease;
        will-change: transform;
    }
    .nav-open .sidebar { transform: translateX(0); }
    .nav-open .scrim { opacity: 1; visibility: visible; }
    .nav-open { overflow: hidden; }

    .sidebar-close { display: inline-flex; }
    .sidebar-nav { padding: .6rem .5rem; }
    .nav-item { padding: .75rem .8rem; font-size: 1rem; }
    .nav-item svg { width: 21px; height: 21px; }
    .sidebar-user { padding: .8rem .9rem calc(.8rem + env(safe-area-inset-bottom)); }

    .main { padding: 1.1rem .9rem 3rem; }
    /* debaixo da topbar (sticky, 56px), nunca por cima dela; a sangria
       acompanha o padding do .main aqui em cima */
    .atalhos { top: var(--topbar-h); margin-left: -.9rem; margin-right: -.9rem; padding-left: .9rem; padding-right: .9rem; }
    .page-head h1 { font-size: 1.3rem; }
    .panel { padding: .9rem .9rem; border-radius: var(--radius); }
    /* cartao do Por produto: o rodape de tres colunas pede ~300px (3 x 92 +
       calhas) — com o padding de desktop ele quebraria em duas linhas a 390px */
    .bar-list-cards > li { padding: .6rem .65rem .55rem; }

    /* Filtros empilhados e chips com rolagem horizontal */
    .filter-bar { flex-direction: column; align-items: stretch; padding: .75rem; }
    /* Os DOIS blocos sao itens flex e nascem com `min-width: auto`: sem o zero
       aqui eles ficam do tamanho do conteudo (307px medidos num viewport de
       320) e quem rola de lado e a PAGINA, nao a faixa de chips. */
    .filter-presets, .filter-fields { min-width: 0; max-width: 100%; }
    .filter-presets {
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        padding-bottom: .15rem;
    }
    .filter-presets::-webkit-scrollbar { display: none; }
    /* minmax(0,1fr) e nao 1fr: o input de data tem largura intrinseca grande e
       com `1fr` (minimo = min-content) ele nao encolhe. Sao DUAS colunas (era
       tres) desde que o rotulo "De"/"Ate" substituiu o separador escrito. */
    .filter-fields { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: end; gap: .5rem; }
    /* sem min-width:0 o campo de data nao encolhe e o grid vaza do card */
    .filter-fields > * { min-width: 0; }
    /* so o par de datas divide a linha; o resto ocupa a largura inteira */
    .filter-fields > .f-campo { grid-column: 1 / -1; }
    .filter-fields > .f-campo:has(input[type="date"]) { grid-column: auto; }
    .filter-fields > .f-campo:has(> input.input-dias) { grid-column: auto; }
    .filter-fields input[type="date"] { width: 100%; }
    .filter-fields select { width: 100%; min-width: 0; }
    .filter-fields > select { grid-column: 1 / -1; }
    .filter-fields .btn { grid-column: 1 / -1; width: 100%; }

    .stat-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: .6rem; }
    /* a reserva do icone e do rotulo (`.stat-label`), nao do card */
    .stat-card { padding: .8rem .85rem; min-height: 104px; }
    .stat-card:has(.stat-ic) .stat-label { padding-right: 2.15rem; } /* icone de 28px + folga */
    .stat-value { font-size: 1.25rem; }
    .stat-qtd { font-size: .8rem; }
    .stat-grid:has(.stat-qtd) .stat-card { min-height: 114px; } /* medido a 390px */
    .stat-ic { top: .7rem; right: .7rem; width: 28px; height: 28px; border-radius: 9px; }
    .stat-ic svg { width: 15px; height: 15px; }

    .form-actions { flex-direction: column-reverse; }
    .form-actions .btn { width: 100%; }
    .field-row .field, .field-row .field.grow { flex: 1 1 100%; }

    .scroll-hint {
        display: block;
        margin: 0 0 .5rem;
        color: var(--muted);
        font-size: .78rem;
    }

    /* Grafico no celular: eixo Y mais estreito e plot mais baixo */
    .chart { --y-w: 46px; --plot-h: 165px; }
    .chart-legend { font-size: .8rem; gap: .3rem .8rem; }
    .chart-tip { font-size: .74rem; max-width: 92vw; }
    .chart-table { padding: .3rem .9rem; }

    /* Tabelas de listagem viram cartoes empilhados. O `tfoot` entra na lista
       (26/10): fora dela ele ficava como grupo de tabela e o cartao do TOTAL
       saia mais estreito que os outros (Por atendente, Caixa, Historico). */
    .table-cards thead { display: none; }
    .table-cards, .table-cards tbody, .table-cards tfoot, .table-cards tr, .table-cards td { display: block; width: 100%; }
    .table-cards tr {
        border: 1px solid var(--border);
        border-radius: var(--radius-sm);
        background: var(--bg-elev);
        padding: .45rem .75rem;
        margin-bottom: .6rem;
    }
    .table-cards tr:hover { background: var(--bg-elev); }
    .table-cards tr:last-child { margin-bottom: 0; }
    .table-cards td {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        flex-wrap: wrap;
        overflow-wrap: anywhere;
        gap: .1rem 1rem;
        padding: .3rem 0;
        border: 0;
        border-bottom: 1px dashed var(--border);
        text-align: right;
    }
    /* chave tecnica (ex.: depositos.confirmar) desce para a propria linha */
    .table-cards td .mono { flex: 1 1 100%; text-align: right; }
    /* ALINHAMENTO DO CARTAO (Bruno, 30/08: "no responsivo ta desalinhado").
       Com `justify-content: space-between` e uma celula de DUAS partes (valor +
       "4x"), o espaco sobrava ENTRE elas: o valor parava no meio da linha e so
       o sufixo encostava na direita — cada linha do cartao com o dinheiro numa
       posicao. Agora o rotulo empurra tudo (`margin-right: auto`), o valor
       principal termina sempre na borda direita e o sufixo desce para a propria
       linha, tambem a direita. */
    .table-cards td::before { margin-right: auto; }
    .table-cards td .cel-sub { flex: 1 1 100%; text-align: right; }
    /* VALOR DE ROTULO COMPRIDO ("Total bicho, loterias e bingo", 26/10):
       quando nao cabe na linha do rotulo ele desce — e desce encostado na
       DIREITA, como os outros valores. Sem isso ficava sozinho na esquerda. O
       `flex-grow` ocupa a sobra da linha; na mesma linha do rotulo o valor
       continua terminando na borda direita. */
    .table-cards td .cel-fim { flex: 1 1 auto; text-align: right; }
    /* no cartao a largura e a da tela: e-mail comprido quebra a linha em vez
       de empurrar o cartao (e a pagina) para o lado */
    .table-cards td .cel-email { white-space: normal; overflow-wrap: anywhere; }
    /* TEXTO CORRIDO (a descricao do atendimento, por exemplo): o alinhamento a
       direita do cartao serve para VALOR — numero, data, badge —, e um
       paragrafo de tres linhas alinhado a direita fica ilegivel. Com
       `cel-texto` o rotulo fica sozinho em cima e o texto desce para a linha
       inteira, lendo da esquerda como todo texto. */
    .table-cards td .cel-texto { flex: 1 1 100%; text-align: left; margin-top: .15rem; }
    /* Capa + nome do jogo (catalogo do cassino): no cartao eles ocupam a
       LINHA INTEIRA, abaixo do rotulo, e leem da esquerda. Disputando a linha
       com o rotulo, a miniatura empurrava o nome para a borda direita e o
       "JOGO" terminava embaixo do que ele nomeia. */
    .table-cards td .cat-jogo { flex: 1 1 100%; margin-top: .15rem; text-align: left; }
    .table-cards td .cat-jogo .cel-main,
    .table-cards td .cat-jogo .cel-sub { text-align: left; }
    .table-cards td:last-child { border-bottom: 0; }
    .table-cards td::before {
        content: attr(data-label);
        flex: 0 0 auto;
        color: var(--muted);
        font-size: .72rem;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: .04em;
        text-align: left;
    }
    .table-cards td[data-label=""] { text-align: left; }
    .cel-main, .cel-sub { text-align: right; }
    /* Os badges ficam a direita mesmo quando quebram para a propria linha
       (com o rotulo longo "Atendente / Plataforma" isso acontece): sem o
       `margin-left: auto` eles voltavam para a esquerda e o cartao ficava com
       dois alinhamentos diferentes. */
    .cel-badges { align-items: flex-end; margin-left: auto; }
    .trunc { cursor: auto; }
    .trunc-curto { display: none; }
    .trunc-full { display: inline; overflow-wrap: anywhere; }
    .table-cards td[data-label=""]::before { display: none; }
    .table-cards td.num { text-align: right; }
    .table-cards td.row-actions { justify-content: flex-end; padding-top: .5rem; }
    .table-cards td.row-actions .btn { flex: 1 1 auto; }
}

/* ============================================================
   Cartao de JOGO no celular (/jogos) — Bruno, 05/09
   ------------------------------------------------------------
   A listagem tem oito colunas e o cartao generico dava a mesma
   voz para todas, cada uma com o rotulo a esquerda e o valor
   colado na direita: quem confere uma aposta procurava loteria,
   modalidade, colocacao, numero, premio possivel e premio pago
   no meio de horario, jogador e atendente, tudo no mesmo corpo.

   Aqui o cartao ganha tres camadas e um so alinhamento (a
   esquerda, como se le):
     1. identidade — loteria grande, situacao fechando a linha;
     2. a aposta   — modalidade, colocacao/numero e os tres
                     valores lado a lado, que e o que se confere;
     3. cadastro   — data, jogador e atendente, em corpo menor
                     e atras de um traco: raramente e o que se
                     procura, mas nao pode sumir.

   Vem DEPOIS do bloco generico de .table-cards de proposito: as
   duas regras tem a mesma especificidade e quem vence e a ultima.
   ============================================================ */
@media (max-width: 900px) {
    .tabela-jogos tr { display: flex; flex-wrap: wrap; align-items: baseline; padding: .55rem .75rem; }
    .tabela-jogos td {
        flex: 1 1 100%;
        /* o bloco generico poe `width: 100%` em toda celula do cartao; como
           item flex isso vira a largura BASE e nao sobrava espaco para a
           loteria crescer ao lado do badge (ela ficava com 0px e o nome do
           sorteio saia letra a letra). Quem manda na largura aqui e o flex. */
        width: auto;
        padding: .12rem 0;
        border-bottom: 0;
        text-align: left;
        justify-content: flex-start;
    }
    /* o `td` no seletor nao e enfeite: a regra generica do cartao e
       `.table-cards td .cel-sub` e sem ele perde por especificidade — era o
       que jogava "JB · PT19" e "1oP · 948" para a direita da tela */
    .tabela-jogos td .cel-main, .tabela-jogos td .cel-sub { text-align: left; }

    /* 1a camada — loteria e situacao na mesma linha. `flex: 1 1 0` (e nao
       `auto`): com base automatica a celula da loteria media o conteudo do
       sub, ocupava a linha inteira e empurrava o badge para baixo. */
    .tabela-jogos td[data-label="Loteria"]  { order: 1; flex: 1 1 0; min-width: 0; }
    /* sem `margin-left: auto` aqui: margem automatica absorve o espaco livre
       ANTES do flex-grow, e a celula da loteria (base 0) ficava com largura
       zero — o nome do sorteio saia quebrado letra a letra. Quem empurra o
       badge para a direita e o proprio crescimento da loteria. */
    .tabela-jogos td[data-label="Situacao"] { order: 2; flex: 0 0 auto; }
    .tabela-jogos td[data-label="Loteria"]::before,
    .tabela-jogos td[data-label="Situacao"]::before,
    .tabela-jogos td[data-label="Aposta"]::before,
    .tabela-jogos td.cel-valores::before { display: none; }
    .tabela-jogos td[data-label="Loteria"] .cel-main { font-size: 1.05rem; font-weight: 700; }
    .tabela-jogos td[data-label="Loteria"] .cel-sub  { flex: 1 1 100%; font-size: .72rem; text-align: left; }

    /* 2a camada — a aposta: modalidade, colocacao e numero */
    .tabela-jogos td[data-label="Aposta"] { order: 3; margin-top: .35rem; }
    .tabela-jogos td[data-label="Aposta"] .cel-main { font-size: .95rem; font-weight: 650; }
    .tabela-jogos td[data-label="Aposta"] .cel-sub {
        flex: 1 1 100%; font-size: .88rem; color: var(--text); text-align: left;
    }
    /* o numero apostado e o dado que se confere: fica junto da colocacao, a
       esquerda e no maior corpo do cartao depois do nome da loteria (a regra
       generica jogava todo .mono para a direita numa linha so dele) */
    .tabela-jogos td[data-label="Aposta"] .cel-sub .mono {
        flex: 0 0 auto; text-align: left; font-weight: 700;
    }
    .tabela-jogos .ja-coloc { display: inline; font-size: .88rem; }
    .tabela-jogos .ja-coloc::after { content: " · "; color: var(--faint); font-weight: 400; }
    .tabela-jogos .ja-num { display: inline; }
    .tabela-jogos .ja-num { font-size: 1.06rem; letter-spacing: .05em; }
    .tabela-jogos .ja-num.is-id { font-size: .76rem; letter-spacing: 0; }

    /* os tres valores lado a lado, rotulo em cima do numero */
    .tabela-jogos td.cel-valores {
        order: 4;
        flex-direction: row;
        flex-wrap: wrap;
        align-items: flex-start;
        gap: .1rem 1.3rem;
        margin: .45rem 0 .15rem;
    }
    .tabela-jogos .v-item { flex-direction: column; align-items: flex-start; gap: 0; }
    .tabela-jogos .v-num  { font-size: .95rem; }
    .tabela-jogos .cel-valores .mono { flex: 0 0 auto; text-align: left; }

    /* resultado do sorteio, com o rotulo em cima; sem sorteio (cassino,
       bingo) a linha inteira sai do cartao */
    .tabela-jogos td[data-label="Resultado"] { order: 5; flex-wrap: wrap; }
    .tabela-jogos td.cel-vazia { display: none; }
    .tabela-jogos td[data-label="Resultado"]::before { flex: 1 1 100%; margin-bottom: .1rem; }

    /* 3a camada — cadastro, em corpo menor e atras de um traco */
    .tabela-jogos td[data-label="Sorteio / Aposta"]        { order: 6; }
    .tabela-jogos td[data-label="Jogador"]                 { order: 7; }
    .tabela-jogos td[data-label="Atendente / Plataforma"]  { order: 8; }
    .tabela-jogos td[data-label="Sorteio / Aposta"],
    .tabela-jogos td[data-label="Jogador"],
    .tabela-jogos td[data-label="Atendente / Plataforma"] {
        justify-content: space-between;
        font-size: .78rem;
    }
    .tabela-jogos td[data-label="Sorteio / Aposta"] {
        margin-top: .45rem;
        padding-top: .45rem;
        border-top: 1px dashed var(--border);
    }
    .tabela-jogos td[data-label="Sorteio / Aposta"]::before,
    .tabela-jogos td[data-label="Jogador"]::before,
    .tabela-jogos td[data-label="Atendente / Plataforma"]::before { font-size: .66rem; }
    /* data e hora ficam na mesma linha, a direita */
    .tabela-jogos td[data-label="Sorteio / Aposta"] .cel-main,
    .tabela-jogos td[data-label="Sorteio / Aposta"] .cel-sub,
    .tabela-jogos td[data-label="Jogador"] .cel-main,
    .tabela-jogos td[data-label="Jogador"] .cel-sub { flex: 0 0 auto; text-align: right; }
    .tabela-jogos td[data-label="Jogador"] .cel-sub,
    .tabela-jogos td[data-label="Sorteio / Aposta"] .cel-sub { flex: 1 1 100%; }
    /* no cartao a lupa fecha o cartao, com rotulo, depois do bloco de cadastro */
    .tabela-jogos td.row-actions { order: 9; padding-top: .5rem; }
    .tabela-jogos td.row-actions .btn-analisar { flex: 0 0 auto; }
    .tabela-jogos td[data-label="Sorteio / Aposta"] .mono { flex: 0 0 auto; }
    /* os dois badges do rodape cabem lado a lado — empilhados gastavam mais
       uma linha do cartao para o dado menos procurado */
    .tabela-jogos td[data-label="Atendente / Plataforma"] .cel-badges {
        flex-direction: row; flex-wrap: wrap; justify-content: flex-end; gap: .3rem;
    }

    /* Numeros do sorteio no cartao: a regra generica dava
       `flex: 1 1 100%; text-align: right` a todo .mono, entao o numero se
       esticava dentro do <li> e cada premio parava numa posicao diferente
       ("os numeros do resultado estao tortos" — Bruno, 05/09). */
    .table-cards td .premios .mono { flex: 0 0 auto; text-align: right; }
    .premios { gap: .05rem .7rem; }
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
    }
}

@media print {
    .topbar, .sidebar, .scrim, .page-actions, .filter-bar, .row-actions { display: none !important; }
    .main { padding: 0; }
    .panel { box-shadow: none; border-color: #ccc; }
}

/* ============================================================
   MODAL (overlay) — primeiro uso: cartao de aniversario.
   Componente compartilhado de proposito: modal escrita inline na
   pagina nasce sem o overlay e o conteudo cai solto no rodape
   (foi o que aconteceu na primeira versao da tela de aniversarios).
   ============================================================ */
.modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: 60;                 /* acima da sidebar (45) e da topbar (40) */
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    background: rgba(8, 10, 16, .62);
    backdrop-filter: blur(2px);
    overflow-y: auto;
}
/* o [hidden] do navegador perde do display:flex acima — repor aqui */
.modal-backdrop[hidden] { display: none; }

.modal {
    position: relative;
    width: min(100%, 460px);
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: 0 18px 48px rgba(0, 0, 0, .38);
    padding: 1.1rem 1.2rem 1.2rem;
}
.modal-lg { width: min(100%, 620px); }
.modal-xl { width: min(100%, 1100px); }   /* tabela larga dentro (detalhe da descarga) */
.modal-title { margin: 0 2rem .8rem 0; font-size: 1.05rem; font-weight: 700; }
.modal .close {
    position: absolute;
    top: .55rem;
    right: .6rem;
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--muted);
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
}
.modal .close:hover { background: var(--surface-3); color: var(--text); }
body.modal-open { overflow: hidden; }

/* Acoes em linha dentro de celula de tabela (WhatsApp/cartao/marcar):
   botoes so-icone alinhados, sem quebrar a coluna em varias alturas. */
.acoes-linha { display: flex; align-items: center; gap: .3rem; flex-wrap: nowrap; }
.btn-icone { min-height: 34px; width: 34px; padding: 0; }
.btn-icone svg { width: 16px; height: 16px; opacity: .85; }
.btn-icone:hover svg { opacity: 1; }
@media (max-width: 900px) {
    .acoes-linha { flex-wrap: wrap; }
}

/* ---- Botao COPIAR (codigo externo do deposito, id de transacao...) ----
   Parece texto, age como botao: o operador cola o codigo no painel do
   adquirente, entao clicar tem que copiar sem precisar selecionar na mao. */
.btn-copiar {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    max-width: 100%;
    padding: .18rem .45rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    color: var(--text);
    font: inherit;
    cursor: pointer;
    transition: background .14s, border-color .14s, color .14s;
}
.btn-copiar:hover { background: var(--surface-3); border-color: var(--border-strong); }
/* ID no banco (`id_banco_btn`): INTEIRO numa linha, a coluna cresce — o
   atendente confere o id de olho. No cartao do celular ele quebra em vez de
   empurrar a pagina para o lado. */
.btn-copiar.btn-copiar-inteiro { white-space: nowrap; }
@media (max-width: 900px) {
    .btn-copiar.btn-copiar-inteiro { white-space: normal; text-align: left; }
    .btn-copiar.btn-copiar-inteiro .mono { overflow-wrap: anywhere; }
}
.btn-copiar svg { flex-shrink: 0; opacity: .55; }
.btn-copiar:hover svg { opacity: .9; }
.btn-copiar.copiado { border-color: var(--green, #16a34a); color: var(--green, #16a34a); }
.btn-copiar.copiado svg { opacity: 1; }

/* Celula com TRES acoes (confirmar/cancelar/analisar nos depositos): o
   `min-width: 108px` de `.row-actions .btn` foi pensado para uma acao so —
   com tres, a coluna estoura 324px, a linha estica e os botoes saem da
   tabela. `.btn-xs` e a versao compacta para esse caso. */
.btn-xs {
    min-height: 30px;
    padding: .25rem .6rem;
    font-size: .8rem;
    font-weight: 550;
}
.row-actions .btn-xs { min-width: 0; }
/* Tres botoes na mesma celula (confirmar/cancelar/analisar). O `nowrap` so
   pode existir porque **um** deles leva texto e os outros dois sao icone: a
   coluna pede ~156px e cabe. Com os tres escritos eram 256px, a tabela de
   depositos passava da largura do painel e o ultimo botao ficava cortado em
   1400px — se algum dia voltar rotulo aqui, tire o nowrap junto. */
.row-actions.acoes-multi { flex-wrap: nowrap; gap: .3rem; }

/* Icone no tamanho da tabela: quadrado, sem calha de texto. A regra existe
   porque `.btn-xs` vem depois de `.btn-icone` no arquivo e devolveria o
   padding lateral, deixando o botao oval. */
.btn-xs.btn-icone { width: 30px; min-width: 30px; min-height: 30px; padding: 0; }

/* Botao que troca de forma por largura: icone no desktop (onde a coluna e
   disputada) e icone + rotulo no cartao do celular. O `title`/`aria-label`
   valem nos dois — leitor de tela e mouse parado nunca ficam sem o nome. */
/* Lupa "analisar jogador", ultima coluna do relatorio de jogos. A coluna
   custava 130px numa tabela que ja passa da area util de um desktop de 1280
   (medido a 1010px: 1042 -> 1172) — e o culpado nao era o icone, era o
   `min-width: 108px` que `.row-actions .btn` da a todo botao de acao (pensado
   para "Confirmar", com texto). Isento aqui, a coluna cobra so o quadrado. */
/* `.btn-avisar` (o sino dos relatorios, 26/10) e o mesmo desenho: quadrado ao
   lado da lupa no desktop, "Avisar" escrito no cartao do celular. */
.row-actions .btn-analisar, .row-actions .btn-avisar { min-width: 0; }
.btn-analisar, .btn-avisar { display: inline-flex; align-items: center; gap: .35rem; }
.btn-analisar svg, .btn-avisar svg { width: 16px; height: 16px; opacity: .85; }
@media (min-width: 901px) {
    .btn-analisar, .btn-avisar { width: 34px; min-width: 34px; padding: 0; justify-content: center; }
    .btn-analisar .btn-lbl, .btn-avisar .btn-lbl { display: none; }
}
/* Sino de quem ja recebeu NESTA visita da pagina: quem segue a lista mandando
   o mesmo aviso ve onde parou. Nao fica gravado — recarregou, some. */
.js-notificar.is-enviado { color: var(--green); border-color: var(--green); }
.js-notificar.is-enviado svg { opacity: 1; }

/* Confirmacao do envio feito pelo modal: o relatorio nao recarrega, entao o
   flash do topo nao serve (com a lista rolada ele nem estaria na tela). */
.toast {
    position: fixed;
    left: 50%;
    bottom: 1.2rem;
    z-index: 70;                 /* acima do modal (60) */
    transform: translateX(-50%);
    max-width: calc(100vw - 2rem);
    padding: .65rem 1rem;
    border: 1px solid var(--ok-border);
    border-radius: var(--radius-sm);
    background: var(--ok-bg);
    color: var(--ok-text);
    font-size: .9rem;
    font-weight: 600;
    box-shadow: 0 10px 28px rgba(0, 0, 0, .28);
}
.btn-xs.btn-icone svg { width: 15px; height: 15px; }
@media (max-width: 900px) {
    .row-actions.acoes-multi { flex-wrap: wrap; }
    .row-actions.acoes-multi .btn-xs { flex: 1 1 auto; }
    /* No cartao do celular quem estica e o botao de TEXTO; icone continua
       quadrado. Precisa casar a especificidade do `.table-cards td.row-actions
       .btn` la de cima (que tem o elemento `td`), senao o `flex: 1 1 auto`
       daquele vence e o icone vira uma barra com uma lupa no meio. */
    .table-cards td.row-actions .btn-icone { flex: 0 0 auto; }
}

/* ============================================================
   Visao por produto (/jogos/visao): dobra e acordeao de grupo
   ------------------------------------------------------------
   A tela empilhava, chapadas, ~55 loterias + quatro tabelas "por dia" — no
   celular cada linha vira cartao de cinco linhas e a pagina passava de dez
   telas de rolagem (Bruno, 30/08: "precisa scrollar muito pra ver"). Agora o
   grupo de sorteio ja mostra o total e so abre as loterias dele quando o
   operador pede, e o "por dia" entra recolhido. <details> de proposito:
   funciona sem uma linha de JS e o navegador cuida do estado.
   ============================================================ */
.bloco-dobra { margin: 1.5rem 0 .7rem; }
.bloco-dobra:first-child { margin-top: 0; }
.bloco-dobra > summary {
    display: flex;
    align-items: center;
    gap: .5rem;
    cursor: pointer;
    list-style: none;
    padding: .2rem 0;
    min-height: 40px; /* alvo de toque */
}
.bloco-dobra > summary::-webkit-details-marker { display: none; }
.bloco-dobra .dobra-t { font-size: 1rem; font-weight: 700; }
.bloco-dobra .dobra-c { font-size: .78rem; margin-left: auto; }
.bloco-dobra .dobra-chev { flex-shrink: 0; opacity: .55; transition: transform .2s; }
.bloco-dobra[open] > summary .dobra-chev { transform: rotate(180deg); }
.bloco-dobra[open] > summary { margin-bottom: .5rem; }
/* Dentro do painel do bicho o titulo do bloco e h3, entao acompanha o tamanho */
section.panel .bloco-dobra .dobra-t { font-size: .95rem; }
section.panel > .bloco-dobra .dobra-t { font-size: 1rem; }

.grupo-acc { display: flex; flex-direction: column; gap: .45rem; }
.grupo-item {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-2);
}
.grupo-item[open] { border-color: var(--border-strong); background: var(--surface); }
.grupo-item > summary {
    display: flex;
    align-items: center;
    gap: .7rem;
    cursor: pointer;
    list-style: none;
    padding: .6rem .8rem;
    min-height: 44px;
}
.grupo-item > summary::-webkit-details-marker { display: none; }
.grupo-item > summary:hover { background: var(--surface-3); border-radius: var(--radius); }
.grupo-item .g-id { flex: 1 1 auto; min-width: 0; }
.grupo-item .g-nome {
    display: block; font-weight: 700; font-size: .92rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.grupo-item .g-sub { display: block; font-size: .72rem; margin-top: 1px; }
/* Os TRES numeros (apostado, premios, resultado) em colunas com rotulo, a
   mesma linguagem do rodape das barras — antes eram dois valores empilhados
   sem rotulo, e o premio nem aparecia (Bruno, 07/09). No desktop eles ficam
   a direita do nome do grupo; quando a linha aperta, a faixa de numeros desce
   inteira para baixo do nome em vez de espremer o rotulo. */
.grupo-item .g-nums {
    flex: 0 0 auto;
    display: grid;
    grid-template-columns: repeat(3, minmax(74px, auto));
    gap: .1rem 1rem;
    line-height: 1.25;
}
.grupo-item .g-nums .bf-val { font-size: .86rem; }
.grupo-item .g-nums .bf-res .bf-val { font-size: .86rem; font-weight: 700; }

@media (max-width: 640px) {
    .grupo-item > summary { flex-wrap: wrap; }
    .grupo-item .g-id { flex: 1 1 auto; }
    /* `order: 3` poe os numeros DEPOIS da seta: assim a primeira linha fica
       "nome ... ⌄" (a seta onde a mao ja procura) e a faixa de numeros desce
       inteira para a segunda. */
    .grupo-item .g-nums {
        order: 3;
        flex: 1 1 100%;
        margin-top: .4rem;
        grid-template-columns: repeat(auto-fit, minmax(92px, 1fr));
        gap: .1rem .7rem;
    }
}
.grupo-item .g-chev { flex-shrink: 0; opacity: .55; transition: transform .2s; }
.grupo-item[open] > summary .g-chev { transform: rotate(180deg); }
.grupo-item > .table-wrap { padding: 0 .5rem .5rem; }
@media (max-width: 560px) {
    .grupo-item > summary { padding: .55rem .6rem; gap: .5rem; }
    .grupo-item .g-nums { font-size: .95em; }
}

/* Loteria dentro do grupo, no celular: linha compacta, nao cartao de cinco
   linhas. O cartao padrao gasta ~145px por loteria — num grupo de 24
   (L-BichoStars) sao 3.500px so de drill, o problema que o acordeao veio
   resolver. Aqui nome e resultado ficam na primeira linha e os numeros de
   apoio embaixo: ~59px por loteria.

   A quebra depois do resultado e feita por um item flex de largura total
   (`tr::before`), nao por grid de posicao fixa: com colunas fixas a loteria
   de volume alto ("Apostado R$ 18.391,77") estourava a terceira coluna e a
   tabela passava a rolar de lado dentro do grupo (medido: celula ate 431px
   numa faixa de 328). Assim os tres numeros se acomodam e, quando nao cabem,
   o ultimo desce sozinho — nunca some para fora da tela.

   Os `data-label` sao o CONTRATO deste layout: a ordem das celulas sai daqui,
   casando pelo rotulo exato (com acento). Quem usa: /jogos/visao e a ficha do
   jogador. Renomear a coluna no template sem renomear aqui joga a celula para
   o comeco da linha, em corpo cheio (foi o que aconteceu na ficha, 05/09). */
@media (max-width: 900px) {
    /* GRADE de tres colunas, nao uma fila de itens flex (Bruno, 07/09: "quando
       expande ta desorganizado"). Com flex, cada celula tinha a largura do seu
       proprio texto: "APOSTADO R$ 8.026,74" comecava num lugar na PT-14:15 e
       noutro na CRJ-21:15, e o rotulo colado no numero ("APOSTAS 4.789")
       fazia a linha parecer uma frase. Em colunas de fracao igual, todas as
       loterias do grupo tem os numeros na mesma posicao e da para descer o
       olho por uma coluna so — e o rotulo sobe para cima do valor, como no
       rodape das barras e no cabecalho do grupo. */
    .lot-mini tr {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        column-gap: .5rem;
        row-gap: .15rem;
        padding: .5rem .6rem;
    }
    .lot-mini td {
        display: block;
        width: auto;
        padding: 0;
        border-bottom: 0;
        text-align: left;
        min-width: 0;
    }
    /* 1a linha: nome (duas colunas) e resultado colado na direita */
    .lot-mini td[data-label="Loteria"] {
        grid-column: 1 / 3; grid-row: 1;
        font-weight: 700;
        overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .lot-mini td[data-label="Resultado"] {
        grid-column: 3; grid-row: 1;
        text-align: right; font-weight: 700;
    }
    /* 2a linha: os tres numeros de apoio, cada um na sua coluna */
    .lot-mini td[data-label="Apostas"]  { grid-column: 1; grid-row: 2; }
    .lot-mini td[data-label="Apostado"] { grid-column: 2; grid-row: 2; }
    .lot-mini td[data-label="Prêmios"]  { grid-column: 3; grid-row: 2; text-align: right; }
    /* Rotulo e valor da MESMA coluna alinhados do mesmo lado: o `.num` da
       celula puxa o numero para a direita (regra base da tabela) e o
       `td::before` do cartao alinha o rotulo a esquerda — cada coluna ficava
       com a etiqueta num canto e o numero no outro. A direita, de quebra, e
       onde dinheiro se compara. */
    .lot-mini td[data-label="Apostas"],
    .lot-mini td[data-label="Apostado"],
    .lot-mini td[data-label="Prêmios"] { font-size: .76rem; text-align: right; }
    .lot-mini td[data-label="Apostas"]::before,
    .lot-mini td[data-label="Apostado"]::before,
    .lot-mini td[data-label="Prêmios"]::before { text-align: right; }
    /* o rotulo vira etiqueta ACIMA do valor (mesma escada do `.bf-rot`) */
    .lot-mini td::before {
        display: block;
        font-size: .62rem; font-weight: 700;
        letter-spacing: .05em;
        color: var(--faint);
        margin: 0;
    }
    .lot-mini td[data-label="Loteria"]::before,
    .lot-mini td[data-label="Resultado"]::before { display: none; }

    /* Os dois atalhos para o relatorio de jogos ocupam a linha inteira,
       embaixo dos numeros e encostados na direita: sao acao, nao dado, entao
       nao podem disputar coluna com os valores que a linha veio mostrar. */
    .lot-mini td.lot-acoes {
        grid-column: 1 / -1;
        grid-row: 3;
        display: flex;
        justify-content: flex-end;
        gap: .35rem;
        margin-top: .4rem;
        padding: 0;
    }
    .lot-mini td.lot-acoes::before { display: none; }
    /* o cartao generico manda `flex: 1 1 auto` em botao de acao (para o botao
       unico ocupar a largura do cartao); aqui sao dois atalhos discretos, que
       nao podem virar duas metades de barra */
    .lot-mini td.lot-acoes .btn { flex: 0 0 auto; }
}

/* ---- Valor do card que nao cabe: a escada de tamanho ----
   Fica no FIM do arquivo de proposito. Ela e `@container`, que nao soma
   especificidade: enquanto morava la em cima, o `.stat-value` do bloco de
   celular (mais abaixo no arquivo) vencia por ordem de fonte e a escada
   simplesmente nao existia no celular — foi assim que o card do mes cheio
   apareceu com "R$ 3.716.166,74" atravessando a borda (medido 30/08: texto
   de 158px numa faixa util de 116px).

   Os limites sao ~45px menores que os antigos porque a largura util do card
   cresceu na mesma medida (a reserva do icone virou padding do rotulo). Quem
   manda e a largura do CARD, nao o tamanho do numero: cards da mesma linha
   tem a mesma largura, entao a linha inteira desce de degrau junta — numero
   grande e vizinho pequeno em corpos diferentes fica pior que ambos menores. */
@container (max-width: 210px) {
    .stat-value { font-size: 1.2rem; }
}
@container (max-width: 165px) {
    .stat-value { font-size: 1.02rem; }
}
/* dois cards lado a lado num aparelho de 360px: a faixa util cai para 134px e
   o valor de sete digitos passaria de 1px de folga */
@container (max-width: 140px) {
    .stat-value { font-size: .92rem; }
}

/* ============================================================
   Select com BUSCA (combobox montado pelo admin.js)
   ------------------------------------------------------------
   O <select> nativo nao procura: com 339 bancos na ficha do jogador (ou 50+
   loterias) achar a opcao e rolagem no escuro (Bruno, 30/08). O componente e
   feito na mao — nada de select2, o painel nao carrega biblioteca de front.

   O botao COPIA a aparencia do select (mesma borda, altura, setinha) de
   proposito: a barra de filtros nao pode virar uma colecao de estilos. O
   <select> original continua no DOM, so escondido — e ele que o formulario
   envia, e sem JS e ele que aparece.
   ============================================================ */
.sel-busca { position: relative; display: inline-block; min-width: 0; max-width: 100%; }
/* `.sel-busca select.sel-oculto` e nao `.sel-oculto`: dentro da barra de
   filtros existe `.filter-fields .f-campo select { width: 100% }`, que tem
   especificidade maior e devolvia a largura ao select escondido — com
   `position: absolute` ele saia 313px para fora e fazia a PAGINA rolar de lado
   (medido: documento de 1703px num viewport de 1440). */
.sel-busca select.sel-oculto {
    /* nao e `display:none`: em `hidden` o browser ignora o campo em validacao
       de formulario e alguns navegadores param de envia-lo em casos de borda.
       Fora da tela + sem foco resolve sem mexer no envio. */
    position: absolute;
    width: 1px; height: 1px; min-width: 0;
    padding: 0; margin: -1px; border: 0;
    clip-path: inset(50%);
    overflow: hidden;
    pointer-events: none;
}
.sel-btn {
    display: inline-flex;
    align-items: center;
    width: 100%;
    min-width: 150px;
    min-height: 42px;
    background: var(--bg-elev);
    color: var(--text);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    padding: .6rem 2.1rem .6rem .75rem;
    font: inherit;
    text-align: left;
    cursor: pointer;
    background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                      linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: right 1.05rem center, right .75rem center;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
    transition: border-color .15s, box-shadow .15s;
}
.sel-btn:focus-visible,
.sel-busca:has(.sel-pop:not([hidden])) .sel-btn {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}
.sel-txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* opcao "todas/nenhuma" escolhida = o filtro esta desligado; o texto fica
   discreto como o placeholder de um campo vazio */
.sel-busca.vazio .sel-txt { color: var(--muted); }

.sel-pop {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 50;                /* acima do conteudo, abaixo do modal (60) */
    min-width: max(100%, 260px);
    max-width: min(92vw, 380px);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-2);
    padding: .4rem;
}
.sel-pop .sel-q { width: 100%; min-height: 38px; margin-bottom: .35rem; }
.sel-lista { max-height: 260px; overflow-y: auto; -webkit-overflow-scrolling: touch; }
/* Grade e nao flex: o rotulo do optgroup vai EMBAIXO do texto da opcao (como
   a sub-linha das listagens), nao ao lado. Lado a lado, "Vitidelalibera (6.135
   jogadores)" + "Recebendo jogador (ultimos 30 dias)" nao cabiam e o nome
   quebrava em duas linhas. O check ocupa a coluna da direita nas duas linhas. */
.sel-item {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: .5rem;
    padding: .45rem .55rem;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: .88rem;
}
.sel-i-txt { grid-column: 1; min-width: 0; }
.sel-item:hover, .sel-item.ativo { background: var(--surface-2); }
.sel-item[aria-selected="true"] { font-weight: 700; }
.sel-item[aria-selected="true"]::after {
    content: "✓";
    grid-column: 2;
    grid-row: 1 / -1;
    align-self: center;
    color: var(--accent);
}
.sel-item[aria-disabled="true"] { opacity: .5; cursor: default; }
/* de que optgroup a opcao veio (o filtro de atendente agrupa por ativo) */
.sel-grupo { grid-column: 1; font-size: .72rem; color: var(--muted); }
.sel-vazio { padding: .6rem .55rem; font-size: .85rem; margin: 0; }

/* Busca dentro do filtro MULTI de checkboxes (mesma dor, outro componente) */
.filtro-multi .fm-busca { width: 100%; min-height: 36px; margin: 0 0 .35rem; }

@media (max-width: 900px) {
    /* no celular o campo ocupa a linha inteira, como o select nativo faz */
    .filter-fields .sel-busca { grid-column: 1 / -1; width: 100%; }
    .sel-btn { min-width: 0; }
    /* painel ancorado ao campo, na largura dele — `position: static` (o que a
       versao mobile do filtro-multi faz) empurraria a pagina toda para baixo */
    .sel-pop { min-width: 100%; max-width: 100%; }
    .sel-lista { max-height: 45vh; }
}

/* ============================================================
   Marketing: banners e campanhas
   ============================================================ */

/* Miniatura da arte na listagem. `contain` e nao `cover`: banner e imagem
   larga, e cortar o meio esconde justamente o texto da promocao. */
/* `display: block` NAO e detalhe: como imagem inline ela carrega o espaco do
   descender da linha e a celula ganhava ~20px de altura invisivel — era o que
   fazia a linha do banner ter 91px enquanto a arte tem 38 (Bruno, 31/08: "a
   altura deve ser por causa da imagem"). `width: 100%` com teto porque a
   coluna e uma fatia da tabela e a miniatura fixa furava a celula. */
.banner-thumb {
    display: block;
    /* QUADRADO fixo, igual para todos (Bruno, 31/08: "padroniza todos
       quadrado"). A caixa era 76x38 e a arte de banner e VERTICAL: cada uma
       aparecia com uma largura diferente dentro do retangulo e a coluna ficava
       torta. Com a caixa quadrada e `contain`, a moldura e sempre a mesma e a
       arte inteira cabe nela, seja em pe ou deitada. */
    width: 46px;
    height: 46px;
    object-fit: contain;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}

/* Dias da semana como chips clicaveis — sete checkboxes em linha ficavam uma
   fileira de caixinhas sem alvo de toque no celular. */
/* "nao sacavel" na sub-linha do bonus: nao e selo (selo disputaria largura e
   quebraria a linha), e a mesma cor de bonus do painel para nao virar so mais
   um texto cinza. */
.nao-sacavel { color: var(--gold); font-weight: 600; }

.dias-semana { display: flex; flex-wrap: wrap; gap: .4rem; }
.dia-chip {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .45rem .6rem;
    min-height: 40px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    background: var(--bg-elev);
    cursor: pointer;
    font-size: .85rem;
    user-select: none;
}
.dia-chip:hover { border-color: var(--accent); }
.dia-chip:has(input:checked) {
    border-color: var(--accent);
    background: var(--accent-soft);
    font-weight: 700;
}
.dia-chip input { margin: 0; }

.check-inline { display: flex; align-items: flex-start; gap: .5rem; cursor: pointer; font-weight: 400; }
.check-inline input { margin-top: .2rem; flex-shrink: 0; }

@media (max-width: 900px) {
    .banner-thumb { width: 76px; height: 38px; }
    /* no cartao o rotulo fica a esquerda e a arte a direita, como os valores */
    .table-cards td .banner-thumb { margin-left: auto; }
}

/* A coluna de acao encolhe para o tamanho dos botoes: nestas duas tabelas
   sobra largura (poucas colunas) e, sem isso, o `width` livre ia todo para a
   ultima celula — o nome da campanha quebrava em quatro linhas com 250px de
   vazio ao lado dos botoes. `width: 1%` + nowrap e o jeito classico de dizer
   "so o que o conteudo pedir" numa tabela de largura total. */
@media (min-width: 901px) {
    /* `fixed` + o <colgroup> do template: as colunas crescem JUNTAS, cada uma
       com a sua fatia. Foi tentativa e erro ate chegar aqui, e as duas pontas
       importam:
       - deixar uma coluna com `width: 100%` (o "col-cresce") resolve a tela
         estreita e cria um vazio de 960px na tela larga, com a data quebrada
         em quatro linhas do lado;
       - `table-layout: auto` puro faz a tabela ficar maior que o container em
         1024px (medido: 816px de tabela num espaco de 674) e ai quem rola e a
         tabela, escondendo a coluna de acao.
       Com o layout fixo o texto quebra DENTRO da celula, que e o comportamento
       previsivel. So no desktop: no celular a tabela vira cartao. */
    .tabela-marketing { table-layout: fixed; }
    /* linha mais baixa: sao duas linhas de texto por celula, nao seis */
    .tabela-marketing th, .tabela-marketing td { padding-block: .4rem; }
    /* `baseline` e a regra do painel (alinha valor com valor), mas aqui uma das
       celulas e uma IMAGEM de 46px: o navegador desce a primeira linha de texto
       das vizinhas ate a base dela e a linha ganhava 25px de altura fantasma
       (medido: 84px de linha para um conteudo de 59px). Pelo topo, a linha
       encolhe para o tamanho do maior conteudo de verdade. */
    .tabela-marketing td { vertical-align: top; }
    /* Titulo em UMA linha: e o unico texto que varia de tamanho de registro
       para registro, e era ele que fazia a lista virar escada (umas linhas com
       duas linhas de texto, outras com uma). O texto inteiro fica no `title`.
       So no desktop: no cartao a largura e a da tela e o nome cabe. */
    /* a linha de apoio um ponto menor: cabe mais texto antes da reticencia
       (o "não sacável · mín. R$ 5,00" da coluna de bonus e o caso apertado) */
    .tabela-marketing .cel-sub { font-size: .72rem; }
    .tabela-marketing .cel-main,
    .tabela-marketing .cel-sub {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    /* Com titulo e sub-linha travados em uma linha cada, TODA linha tem a mesma
       altura — que era o pedido ("cada uma de um tamanho"). O que nao coube sai
       com reticencia e aparece inteiro no `title` de cada celula. */
    .tabela-marketing td.row-actions { vertical-align: middle; }
    /* a caixa da arte tem 46px: a coluna so precisa dela mais a calha */
    .tabela-marketing td .banner-thumb-btn { margin: 0; }
    /* Cabecalho nunca quebra em duas linhas — titulo de coluna partido faz a
       tabela inteira parecer torta. SEM `overflow: hidden` aqui: numa celula de
       tabela ele cria um contexto proprio, a celula deixa de esticar ate a
       altura da linha e a BORDA de baixo dela sobe — o cabecalho aparecia com a
       linha cortada em degrau na coluna dos botoes (Bruno, 31/08). Os titulos
       ja sao curtos; nao precisa de reticencia. */
    .tabela-marketing th { white-space: nowrap; }
    /* Sem `nowrap` aqui: com a coluna em fatia fixa, os dois botoes nao cabem
       lado a lado em 1024px e vazariam para fora da tabela — melhor
       empilharem. Em tela larga eles voltam para a mesma linha sozinhos. */
    .tabela-marketing td.row-actions { text-align: right; }
    /* Badge tambem nao pode furar a coluna: "bônus não sacável" e mais largo
       que a fatia em telas de 1024 e escorria por cima do valor vizinho.
       Dentro DESTAS tabelas ele quebra; no resto do painel segue inteiro. */
    .tabela-marketing td .badge { white-space: normal; max-width: 100%; }
    /* `.row-actions .btn` tem `min-width: 108px` no painel: com dois botoes sao
       224px, e a coluna so passa disso perto de 1900px de tela — abaixo, os
       botoes vazavam para fora da tabela. Aqui eles tem o tamanho do texto. */
    .tabela-marketing td.row-actions .btn { min-width: 0; }
}

/* Entre 901 e 1200px a coluna de acao nao comporta os dois botoes lado a lado
   (com `min-width: 108px` cada, sao 224px numa fatia de ~94px) e eles escorriam
   para fora da tabela — a listagem aparecia com "Inativar" cortado no meio.
   Aqui eles empilham e ocupam a largura da coluna; acima disso voltam para a
   mesma linha sozinhos. */
@media (min-width: 901px) and (max-width: 1200px) {
    /* badge um ponto menor: numa janela de 1024 a coluna de situacao fica com
       ~94px e "Fora da janela" quebrava dentro da pilula */
    .tabela-marketing td .badge { font-size: .7rem; padding: .08rem .4rem; }
    .tabela-marketing td.row-actions { white-space: normal; }
    .tabela-marketing td.row-actions form { display: block; }
    .tabela-marketing td.row-actions .btn { min-width: 0; width: 100%; margin: .15rem 0 0; }
}

/* ---- Visualizador da arte do banner ----
   A miniatura da lista tem 92px: da para reconhecer o banner, nao para
   conferir a promocao. O clique abre a arte no tamanho que couber na tela. */
.banner-thumb-btn {
    display: block;
    padding: 0;
    border: 0;
    background: none;
    cursor: zoom-in;
    max-width: 100%;
    border-radius: var(--radius-sm);
}
.banner-thumb-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--accent-soft);
}
.banner-thumb-btn:hover .banner-thumb { border-color: var(--accent); }
/* No CARTAO a arte vai para a direita, como os valores. A regra estava sem
   media query e, como `.table-cards` e a classe da tabela inteira, ela empurrava
   a miniatura para a direita TAMBEM no desktop — a coluna "Arte" ficava com o
   cabecalho a esquerda e a imagem no fim da celula. */
@media (max-width: 900px) {
    .table-cards td .banner-thumb-btn { margin-left: auto; }
}
@media (min-width: 901px) and (max-width: 1100px) {
    .tabela-marketing td .banner-thumb-btn { margin-left: auto; }
}

/* mais largo que o modal padrao: quem abre quer ver a arte, nao o modal */
.modal-arte { width: min(100%, 900px); }
.arte-palco {
    display: grid;
    place-items: center;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: .6rem;
    /* teto pela ALTURA da janela: banner e imagem alta no mobile e, sem isso,
       o modal passava da tela e o botao de fechar sumia */
    max-height: 70vh;
    overflow: auto;
}
.arte-palco img { max-width: 100%; max-height: 66vh; display: block; }

.arte-abas { display: flex; flex-wrap: wrap; gap: .35rem; margin-bottom: .6rem; }
.arte-abas:empty { display: none; }
.arte-aba {
    padding: .35rem .7rem;
    min-height: 34px;
    border: 1px solid var(--border-strong);
    border-radius: 999px;
    background: var(--bg-elev);
    color: var(--text);
    font: inherit;
    font-size: .82rem;
    cursor: pointer;
}
.arte-aba.ativa { border-color: var(--accent); background: var(--accent-soft); font-weight: 700; }

/* ---- Marketing em janela estreita de desktop: cartao, nao tabela ----
   Entre 901 e 1100px sobram ~674px para seis colunas: a de situacao fica com
   94px e "Fora da janela" quebra DENTRO da propria pilula — foi o que o Bruno
   viu como "quebrado". Em vez de espremer mais, estas duas tabelas entram no
   MESMO modo cartao do celular um pouco mais cedo.

   As regras abaixo sao as do bloco de <=900px com escopo em
   `.tabela-marketing`: mexeu no cartao la, confira aqui. */
@media (min-width: 901px) and (max-width: 1100px) {
    .tabela-marketing { table-layout: auto; }
    .tabela-marketing colgroup { display: none; }
    .tabela-marketing thead { display: none; }
    .tabela-marketing, .tabela-marketing tbody, .tabela-marketing tr, .tabela-marketing td { display: block; width: 100%; }
    .tabela-marketing tr { border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-elev); padding: .45rem .75rem; margin-bottom: .6rem; }
    .tabela-marketing tr:hover { background: var(--bg-elev); }
    .tabela-marketing tr:last-child { margin-bottom: 0; }
    .tabela-marketing td { display: flex; align-items: baseline; justify-content: space-between; flex-wrap: wrap; overflow-wrap: anywhere; gap: .1rem 1rem; padding: .3rem 0; border: 0; border-bottom: 1px dashed var(--border); text-align: right; }
    .tabela-marketing td .mono { flex: 1 1 100%; text-align: right; }
    .tabela-marketing td::before { margin-right: auto; }
    .tabela-marketing td .cel-sub { flex: 1 1 100%; text-align: right; }
    .tabela-marketing td:last-child { border-bottom: 0; }
    .tabela-marketing td::before { content: attr(data-label); flex: 0 0 auto; color: var(--muted); font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; text-align: left; }
    .tabela-marketing td[data-label=""] { text-align: left; }
    .tabela-marketing .cel-main, .tabela-marketing .cel-sub { text-align: right; }
    .tabela-marketing .cel-badges { align-items: flex-end; margin-left: auto; }
    .tabela-marketing .trunc { cursor: auto; }
    .tabela-marketing .trunc-curto { display: none; }
    .tabela-marketing .trunc-full { display: inline; overflow-wrap: anywhere; }
    .tabela-marketing td[data-label=""]::before { display: none; }
    .tabela-marketing td.num { text-align: right; }
    .tabela-marketing td.row-actions { justify-content: flex-end; padding-top: .5rem; }
    .tabela-marketing td.row-actions .btn { flex: 1 1 auto; }
}

/* ============================================================
   CARREGANDO — a tela PARA enquanto a consulta roda
   ------------------------------------------------------------
   Pedido do Bruno (10/09): "falta um loading nas pesquisas —
   quando o relatorio e muito grande os usuarios ficam clicando
   varias vezes". A primeira versao foi uma pilula discreta no
   alto e ele reprovou na hora, com a razao certa: "ta rodando
   com tudo ja carregado, e ta muito pequeno".

   O diagnostico esta na frase. Enquanto o servidor pensa, o
   navegador MANTEM a pagina velha inteira na tela — tabela,
   numeros, botoes, tudo legivel. Um aviso pequeno num canto
   nao briga com isso: a tela continua dizendo "pronto" e o
   girinho parece enfeite quebrado. Entao o aviso nao pode ser
   um detalhe, ele tem que APAGAR a tela velha — e o mesmo veu
   que apaga e o que engole o clique repetido, que era o
   problema de origem.

   Por isso aqui e um veu de tela cheia com uma caixa grande no
   meio, e nao um indicador de canto. Se um dia alguem quiser
   "deixar mais discreto", esta e a decisao que se estaria
   revertendo.

   MOVIMENTO REDUZIDO: o bloco global de `prefers-reduced-motion`
   zera TODA animacao com `!important`, entao a roda pararia num
   quadro qualquer e a barra terminaria fora da tela. O media
   query no fim troca as duas por um estado parado; o texto
   grande no meio da tela nunca dependeu de animacao.
   ============================================================ */

/* Veu: cobre TUDO (menu 45, topbar 40, modal 60) e absorve o
   clique repetido — o segundo clique cai aqui, nao no botao. */
.carregando-tela {
    position: fixed;
    inset: 0;
    z-index: 70;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
    background: var(--scrim);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
    animation: carregando-entra .14s ease-out;
}
@keyframes carregando-entra { from { opacity: 0; } to { opacity: 1; } }
/* `display: flex` acima venceria o [hidden] do navegador (ver BASE) */
.carregando-tela[hidden] { display: none; }

.carregando-caixa {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .55rem;
    width: min(30rem, 100%);
    padding: 2rem 1.6rem 1.7rem;
    border-radius: var(--radius-lg);
    background: var(--bg-elev);
    border: 1px solid var(--border);
    box-shadow: var(--shadow-3);
    text-align: center;
}
.carregando-titulo { font-size: 1.25rem; font-weight: 700; }
/* linha de contexto (`data-carregando` do gatilho): so aparece
   onde a espera de segundos e a regra, tipo "Calcular totais" */
.carregando-det { font-size: .92rem; color: var(--muted); }
.carregando-det[hidden] { display: none; }
/* o recado que resolve o problema de origem — clicar de novo
   joga fora a consulta que ja esta rodando e comeca outra */
.carregando-pare { font-size: .82rem; color: var(--faint); margin-top: .2rem; }

.carregando-roda {
    width: 46px;
    height: 46px;
    margin-bottom: .35rem;
    border: 4px solid var(--surface-3);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: carregando-gira .8s linear infinite;
}
@keyframes carregando-gira { to { transform: rotate(360deg); } }

/* Barra no alto da janela: aparece no MESMO instante do clique
   (a caixa espera 200ms para tela rapida nao piscar), entao ela
   e a unica coisa que responde ao clique de uma tela de 20ms. */
.carregando-barra {
    position: fixed;
    top: 0; left: 0; right: 0;
    height: 4px;
    z-index: 71;
    background: var(--accent-soft);
    overflow: hidden;
}
.carregando-barra::before {
    content: '';
    position: absolute;
    top: 0; bottom: 0; left: 0;
    width: 34%;
    background: linear-gradient(90deg, transparent, var(--accent-hi), transparent);
    animation: carregando-desliza 1.05s ease-in-out infinite;
}
@keyframes carregando-desliza {
    from { transform: translateX(-120%); }
    to   { transform: translateX(320%); }
}

/* O gatilho clicado. `pointer-events: none` segura o clique
   duplo nos 200ms em que o veu ainda nao esta na frente. */
.is-carregando { pointer-events: none; opacity: .6; }
.btn.is-carregando::before {
    content: '';
    flex: 0 0 auto;
    width: 13px;
    height: 13px;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    opacity: .85;
    animation: carregando-gira .8s linear infinite;
}
/* icone proprio do botao sai: dois desenhos no mesmo lugar viram borrao */
.btn.is-carregando > svg { display: none; }

body.carregando, body.carregando .btn, body.carregando a { cursor: progress; }

@media (max-width: 900px) {
    .carregando-caixa { padding: 1.6rem 1.2rem 1.4rem; }
    .carregando-titulo { font-size: 1.15rem; }
    .carregando-roda { width: 40px; height: 40px; }
}

@media (prefers-reduced-motion: reduce) {
    /* Barra parada e cheia: sem animacao ela precisa se sustentar
       como estado, nao como movimento. */
    .carregando-barra::before { animation: none; width: 100%; background: var(--accent); }
    /* Circulo que nao gira nao significa nada: vira um alvo
       parado na cor da marca, e quem avisa e o texto. */
    .carregando-roda { animation: none; border-color: var(--accent); }
    .btn.is-carregando::before { display: none; }
}

@media print {
    .carregando-barra, .carregando-tela { display: none !important; }
}

/* ---- Jogo responsavel: produtos bloqueados por jogador (aba Bloqueios) ----
   Cada produto e uma linha com tres partes: a marcacao (checkbox + nome), o
   prazo e o estado atual. No desktop as tres ficam lado a lado; no celular
   empilham, que e onde a linha de estado precisa caber inteira. */
.bloq-lista { list-style: none; margin: 0 0 1.2rem; padding: 0; }
.bloq-item {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: .4rem 1.2rem;
    align-items: start;
    padding: .85rem .9rem;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface);
}
.bloq-item + .bloq-item { margin-top: .55rem; }
/* Bloqueado ativo ganha a barra vermelha na lateral: numa lista de cinco, o
   que esta VALENDO tem que se achar antes de ler o texto. */
.bloq-item.is-bloqueado { border-color: var(--err-border); box-shadow: inset 3px 0 0 var(--err-text); }

.bloq-check { display: flex; gap: .6rem; align-items: flex-start; cursor: pointer; min-width: 0; }
.bloq-check input { margin-top: .2rem; width: 18px; height: 18px; flex: 0 0 auto; }
.bloq-desc { display: block; margin-top: .1rem; }

.bloq-prazo { display: flex; flex-direction: column; gap: .2rem; }
.bloq-prazo .hint { margin: 0; font-size: .74rem; }

/* O estado ocupa a linha inteira, embaixo das duas colunas */
.bloq-estado { grid-column: 1 / -1; margin: .2rem 0 0; }

@media (max-width: 900px) {
    .bloq-item { grid-template-columns: 1fr; }
    .bloq-prazo > input { width: 100%; }
}

/* ---- Limite diario do cassino (mesma aba, sql/054) ----
   O estado de HOJE em cima do formulario: quanto ele pode, quanto ja foi e
   quanto resta. Atingido ganha a mesma barra vermelha lateral do bloqueio
   ativo — e o que o atendimento procura quando ele diz "nao consigo jogar". */
.limite-estado {
    padding: .85rem .9rem;
    margin-bottom: 1rem;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface);
}
.limite-estado.is-atingido { border-color: var(--err-border); box-shadow: inset 3px 0 0 var(--err-text); }
.limite-valor { margin: 0; font-size: 1.2rem; font-weight: 650; }
.limite-barra {
    height: 8px;
    margin: .55rem 0 .4rem;
    border-radius: 999px;
    background: var(--surface-3);
    overflow: hidden;
}
.limite-barra > span { display: block; height: 100%; background: var(--chart-neutral); }
.limite-estado.is-atingido .limite-barra > span { background: var(--err-text); }

/* ---- Aba Historico da ficha do jogador (vitalicia) ----
   Tres blocos: os cards da vida inteira (usam .stat-grid, que ja existe), os
   "sinais de vida"/preferencias em linha, e a tabela dia a dia. */

/* Sinais de vida e preferencias: pares rotulo/valor que se espalham numa
   linha so no desktop e viram duas colunas no celular. */
.hist-sinais, .hist-pref {
    list-style: none;
    display: grid;
    /* 140px e medido, nao chutado: em 390px sobra ~334px para o conteudo e com
       170px cabia UMA coluna so (2x170 = 340 > 334), deixando meia tela vazia e
       a aba comprida a toa. */
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: .5rem 1.4rem;
    margin: 0 0 .6rem;
    padding: 0;
}
.hist-sinais li, .hist-pref > div {
    display: flex;
    flex-direction: column;
    gap: .1rem;
    padding: .55rem .7rem;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--surface-2);
    min-width: 0;
}
.hist-sinais li > span, .hist-pref dt { font-size: .72rem; text-transform: uppercase; letter-spacing: .05em; font-weight: 650; color: var(--muted); }
.hist-sinais li > strong, .hist-pref dd { margin: 0; font-size: .95rem; font-variant-numeric: tabular-nums; }
.hist-pref dd { overflow: hidden; text-overflow: ellipsis; }

/* Sub-linha dentro da celula (dia da semana, quantidade de apostas). Vale para
   qualquer tabela — nasceu aqui porque a coluna de data carrega duas
   informacoes e o cartao do celular precisa das duas. */
.hist-sub { display: block; margin-top: .1rem; }

/* As quatro colunas de dinheiro da tabela herdam a MESMA cor dos cards e dos
   cabecalhos do painel antigo (verde deposito, azul jogo, vermelho premio,
   laranja saque) — o operador vem de la e acha a coluna pela cor. Aqui a cor
   fica no TEXTO e num fundo de 8%, nao no fundo cheio: celula inteira pintada
   em seis colunas transforma a tabela em bandeira e some com o valor. */
.col-dep { color: var(--green); }
.col-saq { color: var(--red); }
/* .col-jog (azul) e .col-pre (rosa) pegam a cor junto com .ic-blue/.ic-pink,
   mais acima — sao os mesmos dois tons dos cards de aposta e premio, e assim
   os dois temas saem de graca em vez de virarem literal repetida aqui. */
thead .col-dep, thead .col-jog, thead .col-pre, thead .col-saq { font-weight: 700; }

/* Linha de total: e da VIDA INTEIRA, nao da pagina — precisa se destacar da
   ultima linha de dados, senao passa por mais um dia. */
.hist-total > th, .hist-total > td {
    border-top: 2px solid var(--border-strong);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    background: var(--surface-2);
}

@media (max-width: 900px) {
    /* No cartao a cor da coluna continua valendo (e o unico jeito de saber qual
       valor e qual sem o cabecalho), mas o total vira um cartao como os outros */
    .hist-total > th { display: block; }

    /* Celula sem valor SOME do cartao. Na tabela do desktop ela precisa existir
       (e a grade que alinha as colunas), mas no cartao cada celula e uma LINHA:
       sem isto, um dia em que o jogador so apostou ocupa onze linhas, seis
       delas dizendo "nao aconteceu", e a tela vira uma tela por dia.
       Medido no jogador do print: 11 linhas por dia caem para 5-8. */
    .table-cards td.is-vazio { display: none; }
}

/* ================= CONTA CORRENTE (aba da ficha do jogador) =================
   O extrato em ordem com o saldo de cada balde (src/Lib/ContaCorrente.php).
   Os baldes saem em CHIP com o nome escrito; a cor vem das classes .ic-* (os
   mesmos tons validados dos icones dos cards, com os dois temas prontos) e o
   fundo/borda derivam dela por color-mix — nenhuma cor literal nova. */
.cc-chip {
    display: inline-flex;
    align-items: baseline;
    gap: .3rem;
    border: 1px solid color-mix(in srgb, currentColor 38%, transparent);
    background: color-mix(in srgb, currentColor 10%, transparent);
    border-radius: 99px;
    padding: .05rem .5rem;
    font-size: .76rem;
    font-weight: 750;
    line-height: 1.5;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.cc-chip-n { font-weight: 600; }

/* ---- Pode sacar? ---- */
.cc-saque-top { display: flex; flex-wrap: wrap; align-items: flex-end; gap: .4rem 1.4rem; }
.cc-saque-num { display: flex; flex-direction: column; }
.cc-saque-valor {
    font-size: 1.9rem;
    font-weight: 800;
    letter-spacing: -.02em;
    line-height: 1.15;
    font-variant-numeric: tabular-nums;
}
.cc-saque-resp { flex: 1 1 260px; margin: 0 0 .2rem; font-size: .95rem; font-weight: 650; }
.cc-travas { list-style: none; margin: .9rem 0 0; padding: 0; display: grid; gap: .4rem; }
.cc-travas li {
    background: var(--err-bg);
    border: 1px solid var(--err-border);
    color: var(--err-text);
    border-radius: var(--radius-sm);
    padding: .5rem .75rem;
    font-size: .88rem;
    font-weight: 600;
}
.cc-baldes {
    list-style: none;
    margin: 1rem 0 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: .6rem;
}
.cc-baldes li {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: .6rem .75rem;
}
.cc-baldes p { margin: .35rem 0 0; line-height: 1.45; }
.cc-balde-top { display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; }
.cc-balde-v { margin-left: auto; font-variant-numeric: tabular-nums; }
.cc-regras { margin: .8rem 0 0; }

/* ---- Extrato ---- */
.cc-extrato .section-title .small { font-weight: 500; margin-left: .3rem; }
.cc-intro { margin: -.2rem 0 .8rem; }
.cc-partida {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem .6rem;
    align-items: center;
    font-size: .86rem;
    padding: .55rem .75rem;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    margin-bottom: .6rem;
}
.cc-lista { list-style: none; margin: 0; padding: 0; }
/* "Carregar anteriores" (05/11/2026, um registro por linha): no topo da lista,
   traz o bloco de antes; o texto do lado diz quantos ainda faltam */
.cc-mais {
    display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .75rem;
    padding: .55rem 0 .2rem;
}
.cc-dia {
    font-size: .76rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--muted);
    padding: 1rem 0 .35rem;
    border-bottom: 1px solid var(--border-strong);
}
.cc-linha,
.cc-conf {
    display: grid;
    grid-template-columns: 3rem minmax(0, 1fr) auto;
    gap: .2rem .7rem;
    align-items: start;
    padding: .6rem 0;
    border-bottom: 1px solid var(--border);
}
.cc-hora { font-size: .8rem; color: var(--muted); font-variant-numeric: tabular-nums; padding-top: .12rem; }
.cc-corpo { display: flex; flex-direction: column; gap: .2rem; min-width: 0; }
.cc-titulo { font-weight: 700; font-size: .92rem; line-height: 1.3; }
.cc-sub { font-size: .8rem; color: var(--muted); line-height: 1.35; overflow-wrap: anywhere; }
.cc-mov { display: flex; flex-wrap: wrap; gap: .25rem; margin-top: .1rem; }
.cc-alerta { font-size: .8rem; font-weight: 650; color: var(--gold); }
.cc-regra { color: var(--gold); font-weight: 800; margin-left: .15rem; cursor: help; }
/* desktop: valor e olhinho lado a lado (a linha fica baixa); no celular o
   olhinho desce para baixo do valor — la a largura e que falta */
.cc-dir { display: flex; align-items: flex-start; gap: .75rem; text-align: right; }
.cc-num { display: flex; flex-direction: column; align-items: flex-end; gap: .2rem; }
.cc-valor { font-weight: 800; font-size: .95rem; white-space: nowrap; font-variant-numeric: tabular-nums; }
.cc-valor.pos { color: var(--green); }
.cc-valor.neg { color: var(--red); }
.cc-apos { font-size: .74rem; color: var(--muted); white-space: nowrap; }
.cc-apos strong { color: var(--text); font-variant-numeric: tabular-nums; }
.cc-olho {
    width: 40px;
    height: 40px;
    display: grid;
    place-items: center;
    margin-top: .1rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--muted);
    cursor: pointer;
}
.cc-olho svg { width: 17px; height: 17px; }
.cc-olho:hover,
.cc-olho:focus-visible { border-color: var(--accent-line); color: var(--accent-fg); background: var(--accent-soft); }
/* PIX nao pago, lancamento que nao mexe em saldo: fica, mas nao disputa o olho */
.cc-linha.is-mudo .cc-titulo { color: var(--muted); font-weight: 600; }

/* Conferencia com a foto oficial dos saldos: ok e discreta, diferenca chama */
.cc-conf { font-size: .84rem; }
.cc-conf-ico {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-weight: 800;
    font-size: .78rem;
}
.cc-conf.is-ok { color: var(--muted); }
.cc-conf.is-ok .cc-conf-ico { background: var(--ok-bg); color: var(--ok-text); border: 1px solid var(--ok-border); }
/* mesmos tons do .callout-alerta / .badge-warn: dourado = atencao no painel */
.cc-conf.is-dif { background: rgba(180, 130, 10, .08); border-left: 3px solid var(--gold); padding-left: .4rem; }
.cc-conf.is-dif .cc-conf-ico { background: rgba(180, 130, 10, .14); color: var(--gold); border: 1px solid rgba(180, 130, 10, .4); }
.cc-conf-corpo { display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
.cc-conf-sac { font-size: .74rem; color: var(--muted); white-space: nowrap; text-align: right; padding-right: .2rem; }
.cc-conf-sac strong { color: var(--text); }
.cc-rodape { margin: 1rem 0 0; line-height: 1.5; }

/* ---- Olhinho (modal) ---- */
.cc-dt-baldes,
.cc-dt-jogos { width: 100%; border-collapse: collapse; font-size: .85rem; margin-top: .2rem; }
.cc-dt-baldes td,
.cc-dt-jogos td { padding: .4rem .3rem; border-bottom: 1px solid var(--border); vertical-align: baseline; }
.cc-dt-baldes td.num,
.cc-dt-jogos td.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.cc-dt-baldes td.pos { color: var(--green); font-weight: 700; }
.cc-dt-baldes td.neg { color: var(--red); font-weight: 700; }
.cc-dt-sacavel { margin: .7rem 0 0; font-size: .88rem; }
.cc-nota { margin: .5rem 0 0; font-size: .84rem; line-height: 1.45; }
.cc-j-num { display: block; font-weight: 700; overflow-wrap: anywhere; }
.cc-j-mod { display: block; color: var(--muted); font-size: .8rem; }
.cc-j-pago { display: flex; flex-wrap: wrap; gap: .25rem; align-items: center; font-size: .78rem; color: var(--muted); margin-top: .2rem; }

@media (max-width: 560px) {
    .cc-saque-valor { font-size: 1.6rem; }
    .cc-baldes { grid-template-columns: 1fr; }
    .cc-linha,
    .cc-conf { grid-template-columns: 2.5rem minmax(0, 1fr) auto; gap: .15rem .5rem; }
    .cc-hora { font-size: .74rem; }
    .cc-titulo { font-size: .88rem; }
    .cc-valor { font-size: .9rem; }
    .cc-dir { flex-direction: column; align-items: flex-end; gap: .2rem; }
}

/* ============================================================
   ATIVIDADE DA EQUIPE (/auditoria/atividade, 26/10) — o log de trabalho
   ------------------------------------------------------------
   Barras por hora: 24 colunas finas, a altura e a quantidade de
   registros naquela hora em relacao a hora mais cheia da pessoa.
   Mostram o desenho do dia (quando comecou, onde parou, almoco)
   sem precisar ler a linha do tempo inteira.
   ============================================================ */
.atv-horas { display: inline-flex; align-items: flex-end; gap: 1px; height: 22px; vertical-align: middle; }
.atv-horas i { display: block; width: 4px; height: var(--v); min-height: 2px; border-radius: 1px; background: var(--accent); }
.atv-horas i.zero { background: var(--border); }
.atv-horas-g { height: 56px; gap: 3px; }
.atv-horas-g i { width: 10px; }
.atv-eixo { display: flex; justify-content: space-between; width: calc(24 * 13px - 3px); margin-top: .2rem; }
.atv-eixo i { font-style: normal; font-size: .7rem; color: var(--muted); }
.atv-topo { display: grid; grid-template-columns: auto 1fr; gap: 1.2rem 2rem; align-items: start; }
.atv-top { display: flex; flex-wrap: wrap; gap: .35rem; }
.atv-top .chip strong { margin-left: .25rem; }
.atv-quem { margin: 0 0 .9rem; display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
/* quem nao apareceu no periodo: a linha fica, apagada — "sumiu" e informacao */
.tabela-atividade tr.atv-sem td { opacity: .7; }
/* GET (so viu) em peso normal; o que GRAVOU fica em negrito na linha do tempo */
.tabela-tempo .cel-main.atv-viu { font-weight: 450; }
.tabela-tempo td.atv-gap-longo { color: var(--gold); font-weight: 700; }
.tabela-tempo tr.atv-pausa td {
    background: rgba(180, 130, 10, .10);
    color: var(--gold);
    font-size: .85rem;
    text-align: center;
    border-top: 1px dashed rgba(180, 130, 10, .45);
    border-bottom: 1px dashed rgba(180, 130, 10, .45);
}
@media (max-width: 900px) {
    .atv-topo { grid-template-columns: 1fr; }
    .atv-horas-g i { width: 8px; }
    .atv-eixo { width: calc(24 * 11px - 3px); }
    /* A LINHA DO TEMPO no celular: um evento por LINHA (hora · o que · ate a
       proxima), nao o cartao de tres linhas das outras tabelas — um dia de
       150 eventos virava 18 mil pixels de rolagem. */
    .table-cards.tabela-tempo tr {
        display: grid;
        grid-template-columns: auto 1fr auto;
        align-items: baseline;
        gap: 0 .6rem;
        padding: .4rem .6rem;
        margin-bottom: .3rem;
    }
    .table-cards.tabela-tempo td { display: block; padding: 0; border: 0; text-align: left; }
    .table-cards.tabela-tempo td::before { display: none; }
    .table-cards.tabela-tempo td.num { text-align: right; }
    .table-cards.tabela-tempo .cel-main,
    .table-cards.tabela-tempo .cel-sub { text-align: left; }
    .table-cards.tabela-tempo tr.atv-pausa { display: block; }
    .table-cards.tabela-tempo tr.atv-pausa td { text-align: center; }
}

/* ============================================================
   FECHAMENTO DO MES (/financeiro/fechamento, 27/10)
   A conta linha a linha (+, −, =): o texto com o PORQUE embaixo, o valor a
   direita. Duas colunas cabem em 390px, entao NAO vira cartao como as
   listagens — uma conta partida em dez cartoes deixa de se ler como conta.
   ============================================================ */
.fech-conta { width: 100%; border-collapse: collapse; font-size: .92rem; }
.fech-conta td { padding: .55rem .5rem; border-bottom: 1px solid var(--border); vertical-align: baseline; }
.fech-conta td.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; font-weight: 600; padding-left: 1rem; }
.fech-conta .cel-sub { font-size: .8rem; margin-top: .1rem; line-height: 1.4; }
.fech-conta tr.fech-total > td { font-weight: 700; background: var(--surface-2); border-top: 1px solid var(--border-strong); }
.fech-conta tr.fech-total .cel-sub { font-weight: 400; }
.fech-conta tr.fech-final > td { font-size: 1.04rem; }
/* o saldo real digitado: campo + botoes na mesma faixa, quebrando no celular */
.fech-caixa { margin-top: 1.1rem; padding-top: 1rem; border-top: 1px dashed var(--border); max-width: 640px; }
.fech-caixa-acoes { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-top: .5rem; }
/* No celular a coluna do texto ficava com ~200px e o porque virava uma
   escada de seis linhas. Aqui cada linha vira GRADE: rotulo e valor lado a
   lado, o porque embaixo na largura toda (o `td` do texto some com
   `display: contents` e os dois spans viram itens da grade). */
@media (max-width: 900px) {
    .fech-conta, .fech-conta tbody { display: block; }
    .fech-conta tr {
        display: grid;
        grid-template-columns: 1fr auto;
        grid-template-areas: "rot val" "sub sub";
        column-gap: .6rem;
        align-items: baseline;
        padding: .5rem .25rem;
        border-bottom: 1px solid var(--border);
    }
    .fech-conta td { padding: 0; border: 0; }
    .fech-conta td:first-child { display: contents; }
    .fech-conta .cel-main { grid-area: rot; text-align: left; }
    .fech-conta .cel-sub { grid-area: sub; text-align: left; }
    .fech-conta td.num { grid-area: val; display: block; font-size: .88rem; padding-left: 0; }
    .fech-conta tr.fech-total { background: var(--surface-2); border-top: 1px solid var(--border-strong); }
    .fech-conta tr.fech-total > td { background: none; border-top: 0; }
}

/* Faixas da campanha de GIROS GRATIS (Marketing > Campanhas, sql/070): uma
   linha por faixa — deposito minimo, giros e remover — tambem no celular. Com o
   .field-row de sempre cada faixa virava tres blocos empilhados a 390px. */
.faixas-giros { display: flex; flex-direction: column; gap: .5rem; margin-bottom: .5rem; }
.faixa-giros { display: grid; grid-template-columns: minmax(0, 1fr) 6rem auto; gap: .5rem; align-items: end; }
.faixa-giros .field { margin: 0; }
.faixa-giros .field input { width: 100%; }
.faixa-giros + .faixa-giros label { display: none; }

/* ============================================================
   Cartao do RANKING no celular (/jogadores) — Bruno, 05/11
   ------------------------------------------------------------
   "melhora a visualizacao no mobile": o cartao generico dava uma
   LINHA para cada uma das 15 colunas (rotulo a esquerda, valor a
   direita) e o jogador #1 ocupava a tela inteira. Agora: posicao,
   jogador e badges em cima, na largura toda; os numeros numa grade
   de DUAS colunas, rotulo em cima e valor embaixo, em pares que se
   leem juntos — saldo inicial/final, depositos/saques,
   apostas/premios, GGR/dep-saque, bonus/comissao e os dois "dias
   sem". A ordem dos pares vem de `order` (o DOM segue o desktop).
   Vem DEPOIS do bloco generico de .table-cards de proposito.
   ============================================================ */
@media (max-width: 900px) {
    .tabela-ranking tr {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        column-gap: 1rem;
        padding: .55rem .8rem .6rem;
    }
    .tabela-ranking td {
        width: auto;
        min-width: 0;
        flex-direction: column;
        align-items: flex-start;
        justify-content: flex-start;
        gap: .05rem;
        text-align: left;
        padding: .35rem 0;
        order: 20;
    }
    .tabela-ranking td::before { margin-right: 0; font-size: .64rem; }
    .tabela-ranking td .cel-main,
    .tabela-ranking td .cel-sub,
    .tabela-ranking td .cel-fim { flex: none; text-align: left; }
    .tabela-ranking td.num { text-align: left; }

    /* cabecalho do cartao: posicao + jogador + badges, largura toda */
    .tabela-ranking td.rank-col,
    .tabela-ranking td[data-label="Jogador"],
    .tabela-ranking td[data-label="Atendente / Plataforma"],
    .tabela-ranking td.row-actions { grid-column: 1 / -1; }
    .tabela-ranking td.rank-col { order: 1; padding: 0; border-bottom: 0; }
    .tabela-ranking td.rank-col::before { display: none; }
    .tabela-ranking td.rank-col .rank { font-size: .78rem; color: var(--muted); font-weight: 700; }
    .tabela-ranking td[data-label="Jogador"] { order: 2; padding-top: .1rem; }
    .tabela-ranking td[data-label="Jogador"]::before,
    .tabela-ranking td[data-label="Atendente / Plataforma"]::before { display: none; }
    .tabela-ranking td[data-label="Jogador"] .cel-main { font-size: 1.02rem; }
    .tabela-ranking td[data-label="Atendente / Plataforma"] { order: 3; padding: .4rem 0; }
    .tabela-ranking td[data-label="Atendente / Plataforma"] .cel-badges {
        flex-direction: row; flex-wrap: wrap; gap: .35rem; margin-left: 0; align-items: center;
    }

    /* os pares, na ordem de leitura */
    .tabela-ranking td[data-label="Saldo inicial"]      { order: 4; }
    .tabela-ranking td[data-label="Saldo final"]        { order: 5; }
    .tabela-ranking td[data-label="Depositos"]          { order: 6; }
    .tabela-ranking td[data-label="Saques"]             { order: 7; }
    .tabela-ranking td[data-label="Apostas"]            { order: 8; }
    .tabela-ranking td[data-label="Premios"]            { order: 9; }
    .tabela-ranking td[data-label="GGR"]                { order: 10; }
    .tabela-ranking td[data-label="Dep − Saque"]        { order: 11; }
    .tabela-ranking td[data-label="Bonus"]              { order: 12; }
    .tabela-ranking td[data-label="Comissão"]           { order: 13; }
    .tabela-ranking td[data-label="Dias sem jogar"]     { order: 14; }
    .tabela-ranking td[data-label="Dias sem depositar"] { order: 15; }
    /* a coluna que ordena o ranking continua marcada, sem esticar o fundo
       ate a borda do cartao */
    .tabela-ranking td.is-sorted { border-radius: 6px; padding-left: .4rem; padding-right: .4rem; }

    .tabela-ranking td.row-actions {
        order: 30; flex-direction: row; align-items: stretch; gap: .5rem; padding-top: .55rem; border-bottom: 0;
    }
}
