/* Tradução PT/EN — mesmas 3 regras já usadas no site
   (hero.ejs/documentacao.ejs/termos.ejs/portal.ejs), centralizadas aqui
   pra valer em TODO o dashboard de uma vez (esse arquivo é compartilhado
   por moderacao/reports/events/perfil/perfil-denuncias.ejs) — o botão
   que troca html[data-lang] mora em partials/sidebar-v2.ejs, incluído
   por essas mesmas páginas. */
[data-i18n-en] { display: none; }
html[data-lang="en"] [data-i18n-pt] { display: none; }
html[data-lang="en"] [data-i18n-en] { display: initial; }

/* Tamanho padrão de todo ícone Lucide do site (1em = acompanha o
   font-size do elemento pai) — o Lucide (createIcons()) preserva o
   atributo data-lucide no <svg> final, então essa regra pega tanto o <i>
   original quanto o <svg> renderizado. Qualquer regra mais específica já
   existente (ex: .species-chart-count i[data-lucide]) continua vencendo
   essa aqui normalmente pela cascata. */
i[data-lucide] {
    display: inline-flex;
    width: 1em;
    height: 1em;
    vertical-align: -0.15em;
}

/* Isso garante que o fundo escuro cubra a tela toda, sem falhas */
html, body {
    background-color: #1F1D20 !important; /* Usei a cor titan-bg do seu config */
    color: #F8DCC0;
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
    overflow-x: hidden;
}

/* public/css/style.css */
:root {
    --bg-main: #1F1D20;
    --bg-sidebar: #252326;
    --bg-card: #2A2A2A;
    --text-primary: #F8DCC0;
    --text-secondary: #A89986;
    --accent: #DCA15E;
    --surface: #803E30;
    --surface-hover: #4B2427;
    --stroke: #5A1811;
    --font-head: 'Tilt Warp', cursive;
    --font-body: 'Poppins', sans-serif;

    /* Escala de tipografia — Tilt Warp pra Heading/Subtítulo, Poppins pro
       corpo de texto. Valores abaixo são o padrão MOBILE (<768px, mesmo
       breakpoint md do Tailwind já usado no site pra logo/drawer mobile);
       a media query logo abaixo redefine só o que CRESCE em telas
       maiores — Body fica de propósito FIXO em 16px nas duas larguras,
       não é uma escala que sobe junto com os headings. --btn-icon-size
       mora aqui pelo mesmo motivo (ícone de botão: 12x12 mobile, 20x20
       web, mesmo corte). Heading/Subtítulo/Heading-sm formam 3 degraus
       que sobem 1 posição cada (heading-sm mobile 20 = ~heading-sm web
       24, etc.) — Body-sm e Body-xs não têm valor maior pro web, de
       propósito, então ficam com o MESMO número nas duas larguras. */
    --fs-heading: 32px;
    --fs-subtitle: 24px;
    --fs-heading-sm: 20px;
    --fs-body-lg: 16px;
    --fs-body: 16px;
    --fs-body-sm: 14px;
    --fs-body-xs: 12px;
    --fs-caption: 12px;
    --btn-icon-size: 12px;
}

@media (min-width: 768px) {
    :root {
        --fs-heading: 48px;
        --fs-subtitle: 32px;
        --fs-heading-sm: 24px;
        --fs-body-lg: 18px;
        --fs-caption: 13px;
        --btn-icon-size: 20px;
    }
}

/* Classes utilitárias da escala acima — usar em vez de font-size/family
   soltos sempre que o elemento for genuinamente um destes 6 papéis
   (título de página, subtítulo de seção, rótulo pequeno tipo "eyebrow",
   corpo de texto grande/padrão/pequeno, ou legenda/metadado). Não
   aplicadas retroativamente a .section-title nem a nenhum heading já
   em uso — várias páginas escolhem o tamanho de .section-title por
   Tailwind (text-lg/text-2xl/etc.) por instância, forçar um font-size
   fixo aqui quebraria essa variação existente sem necessidade. */
.tp-heading { font-family: var(--font-head); font-size: var(--fs-heading); }
.tp-subtitle { font-family: var(--font-head); font-size: var(--fs-subtitle); }
.tp-heading-sm { font-family: var(--font-head); font-size: var(--fs-heading-sm); }
.tp-body-lg { font-family: var(--font-body); font-size: var(--fs-body-lg); }
.tp-body { font-family: var(--font-body); font-size: var(--fs-body); }
.tp-body-sm { font-family: var(--font-body); font-size: var(--fs-body-sm); }
.tp-body-xs { font-family: var(--font-body); font-size: var(--fs-body-xs); }
.tp-caption { font-family: var(--font-body); font-size: var(--fs-caption); }

body {
    background-color: var(--bg-main);
    color: var(--text-primary);
    margin: 0;
    display: flex;
    height: 100vh;
    box-sizing: border-box; /* Garante que o padding não quebre o layout */
    gap: 30px; /* Espaço entre sidebar e conteúdo principal */
}

/* <main> é flex-1 (cresce E encolhe) dentro de <body>{display:flex}, mas
   um item flex nunca encolhe menos que a largura do seu PRÓPRIO conteúdo
   por padrão (min-width:auto implícito) — se algum filho lá dentro tiver
   largura mínima maior que o espaço disponível (ex: texto com
   white-space:nowrap tipo .outline-chip-headline, ou um .news-grid com
   overflow-x:auto tentando abrir espaço pro próprio carrossel), o <main>
   INTEIRO se recusa a encolher e empurra a página pra rolar de lado,
   cortando o resto do conteúdo em telas estreitas — mesmo em páginas SEM
   sidebar nenhuma (ver <main> de hero.ejs), já que body{display:flex} é
   a base compartilhada de toda página. min-width:0 é a correção padrão
   pra esse comportamento: deixa o <main> encolher até o espaço real
   disponível, e quem precisar rolar horizontalmente por dentro (como
   .news-grid, que já tem overflow-x:auto de propósito, ver hero.ejs)
   passa a rolar DENTRO de si mesmo em vez de arrastar a página inteira
   junto. */
body > main { min-width: 0; }

/* --- BASE PREMIUM DA SIDEBAR (visual antigo, sem mudança) --- */
.sidebar {
    background: linear-gradient(180deg, #252326 0%, #1F1D20 54.34%, #131314 98.29%);
    border-radius: 24px;
    box-shadow: -15px 30px 50px rgba(0, 0, 0, 0.8),
                inset 0.5px 0.5px 0px rgba(248, 220, 192, 0.12);
    border: 1px solid rgba(0, 0, 0, 0.4);
}

/* --- CARD: visual PADRÃO de "sessões padrão" (pedido do dono,
   2026-09-10) — era só o card do Figma "Frame 20"/"BgGradient"+
   "CardShadow", escopado em .tp-config-page (Moderação/Eventos/
   Reports/Game Server/Loja de Jogo); virou o comportamento BASE de
   .titan-card-premium pro site inteiro, sem precisar mais do escopo.
   Exceções que MANTÊM o visual antigo (linear-gradient/24px/borda),
   por já terem passado pela própria rodada de Figma e o dono ter
   pedido explicitamente pra preservar: .pf-id-card (identidade do
   Perfil, ver override em perfil.ejs) — Loja e Inventário usam esse
   visual novo normalmente (o design próprio deles é o item/card de
   compra em si, não o <section> que os envolve). */
.titan-card-premium {
    background: radial-gradient(225.25% 94.36% at 0% 86.37%, #111111 0%, #1F1D20 57.07%, #29272A 91.53%);
    box-shadow: 0.5px -0.5px 0.5px #F8DCC0, -25px 47px 68.1px rgba(0, 0, 0, 0.74);
    border-radius: 20px;
    display: flex;
    padding: 40px;
    width: 100%;
    box-sizing: border-box;
}
/* Padding reduzido no mobile — os 40px fixos valem em qualquer largura;
   somados ao padding lateral do <main> que envolve as sections (removido
   no mobile, ver events.ejs e as outras páginas que compartilham o
   mesmo <main>), 40px de cada lado só do CARD já recriava uma margem
   lateral desperdiçada, então reduzir só aqui não resolvia nada
   sozinho. */
@media (max-width: 767px) {
    .titan-card-premium { padding: 18px; }
}


/* --- TÍTULOS (As fontes que não carregaram no seu print) --- */
/* Rascunho "Padrão de Tipografia" (2026-09-10): text-lg (18px) já era o
   tamanho de fato de ~35 dos ~52 .section-title do site — formalizado
   aqui como o PADRÃO da classe (via --fs-body-lg, o mesmo degrau já
   confirmado na escala de style.css:41-102), então as páginas que já
   usavam text-lg continuam idênticas no desktop e ganham responsividade
   mobile (16px) de graça. Peso 600 junto, mesma ideia. Só os poucos
   outliers precisam de ajuste manual no HTML — ver abaixo do bloco de
   telas do dashboard (dev-*.ejs, gameserver.ejs) onde text-xl/text-base
   foram removidos por caírem no padrão, e loja.ejs/perfil.ejs/
   staff-perfil.ejs onde text-2xl virou .tp-heading-sm (título de página
   inteira, um degrau acima do resto). hero.ejs/documentacao.ejs/
   portal.ejs continuam intocados — têm sua PRÓPRIA .section-title num
   <style> local, que já vence esta por ordem no documento. */
.section-title {
    font-family: 'Tilt Warp', cursive;
    font-size: var(--fs-body-lg);
    font-weight: 600;
    color: #F8DCC0;
    text-transform: uppercase;
    letter-spacing: 2px;
}

/* Título tipo "IN GAME" (Poppins fino, bem espaçado, branco, centralizado)
   — movido de partials/ingame-pulse.ejs pra cá pra virar classe global:
   "Punições"/"Automoderação" de moderation-stats.ejs usam o mesmo
   espaçamento/fonte/tamanho do título IN GAME acima delas. */
.ingame-pulse-title {
    font-family: 'Poppins', sans-serif;
    font-weight: 400;
    font-size: clamp(12px, 1.6vw, 18px);
    line-height: 1.5;
    letter-spacing: 0.3em;
    color: #FFFFFF;
    text-align: center;
    text-transform: uppercase;
}

/* --- SIDEBAR: Comportamento de Barra Lateral --- */
.sidebar {
    width: 320px;
    min-width: 320px; /* Impede que ela esmague */
    height: calc(100vh - 60px); /* Altura total menos margem */
    margin: 30px 0 30px 30px;
    display: flex;
    flex-direction: column;
    padding: 40px 20px;
}

.logo-titans {
    width: 180px;
    margin-bottom: 40px;
    filter: drop-shadow(0 10px 15px rgba(0,0,0,0.6));
}

.nav-item {
    font-family: var(--font-head);
    text-decoration: none;
    color: var(--text-secondary);
    background: rgba(0, 0, 0, 0.2); /* Mais escuro para dar profundidade */
    padding: 14px;
    border-radius: 14px;
    text-align: center;
    border: 1px solid rgba(248, 220, 192, 0.05); /* Borda fantasma */
    transition: all 0.3s ease;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    font-size: 0.85rem;
}

.nav-item:hover {
    background: var(--surface-hover);
    color: var(--text-primary);
    transform: translateY(-2px); /* Efeito de levitação em vez de pro lado */
    box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}

/* GRÁFICOS: Ajuste de espessura e centralização */
.circle-bg {
    fill: none !important;
    stroke: rgba(255, 255, 255, 0.05); /* Um cinza bem clarinho para o trilho */
    stroke-width: 14;
}

.circle-main {
    fill: none !important;
    stroke-width: 14;
    stroke-linecap: butt;
}

.chart-label-container span:first-child {
    font-family: var(--font-head);
    letter-spacing: 1px;
}

/* Classes de Utilidade */
.color-gold { stroke: var(--accent); }
.color-dark-red { stroke: var(--surface); }

/* GRÁFICO DE BARRAS (bar-chart.ejs) — série diária, sem lib externa */
.bar-chart-card {
    background: #131314;
    border: 1px solid rgba(220, 161, 94, 0.2);
    border-radius: 16px;
    padding: 20px;
    display: flex;
    flex-direction: column;
    gap: 18px;
}
.bar-chart-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.bar-chart-title { font-family: 'Tilt Warp', cursive; font-size: 15px; color: #F8DCC0; }
.bar-chart-subtitle { font-family: 'Poppins', sans-serif; font-size: 11px; opacity: 0.5; margin-top: 3px; line-height: 1.4; }
.bar-chart-total { font-family: 'Bebas Neue', sans-serif; font-size: 26px; letter-spacing: 1px; flex: none; }
.bar-chart-bars { display: flex; align-items: flex-end; gap: 4px; height: 155px; }
.bar-chart-col { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; height: 100%; gap: 4px; }
/* Zona de altura FIXA só pra barra (mesmo motivo de .species-chart-track
   em species-playtime-chart.ejs) — sem isso, o valor acima da barra
   (.bar-chart-value, abaixo) divide altura com ela dentro do
   flex-column, e a % de height da barra passa a computar contra um
   espaço variável em vez do track inteiro, encolhendo a barra errado. */
.bar-chart-track { width: 100%; height: 120px; display: flex; align-items: flex-end; justify-content: center; }
.bar-chart-value { font-family: 'Poppins', sans-serif; font-weight: 600; font-size: 11px; color: #F8DCC0; opacity: 0.85; white-space: nowrap; }
.bar-chart-bar { width: 100%; max-width: 22px; border-radius: 4px 4px 0 0; min-height: 2px; opacity: 0.85; transition: opacity 0.15s ease; }
.bar-chart-col:hover .bar-chart-bar, .bar-chart-col.is-tapped .bar-chart-bar { opacity: 1; }
.bar-chart-day { font-family: 'Poppins', sans-serif; font-size: 9px; opacity: 0.4; white-space: nowrap; }
/* Mobile: 14 rótulos "DD/MM" lado a lado não cabem, então ficam
   escondidos por padrão — mas o dia some de vez, sem jeito de ver qual
   barra é qual (item #11 da auditoria de responsividade 2026-09-27).
   Tocar numa barra (ver script no fim de bar-chart.ejs, que alterna
   .is-tapped) revela só o rótulo DAQUELA barra. */
@media (max-width: 640px) {
    .bar-chart-day { display: none; }
    .bar-chart-col.is-tapped .bar-chart-day { display: block; opacity: 0.9; color: #DCA15E; }
}

/* RANKING VERTICAL POR ESPÉCIE (species-playtime-chart.ejs) — reaproveita
   .bar-chart-card/.bar-chart-head acima como moldura, mesmo espírito de
   .bar-chart-bars/.bar-chart-col/.bar-chart-bar só que:
    - coluna com largura PRÓPRIA (min-width), não flex:1 dividindo o
      card em partes iguais — bar-chart.ejs sempre tem um nº fixo de
      dias (cabe sem rolar); aqui o nº de espécies varia, então rola
      horizontalmente (overflow-x:auto) em vez de espremer rótulos.
    - valor (horas) ACIMA da barra, maior que .bar-chart-day — aqui é o
      dado principal do gráfico, não uma legenda de eixo.
    - a barra em si mora dentro de .species-chart-track, uma zona de
      altura FIXA dedicada só a ela — NÃO divide altura em flex com
      valor/nome/contagem (esses têm altura própria de conteúdo, fora
      dessa zona). Sem isso, uma barra pedindo height:100% competia por
      espaço com os 3 textos dentro do MESMO orçamento de altura da
      coluna, e o motor de flex-shrink podia (dependendo do navegador)
      espremer/cortar o texto do valor em vez de só encolher a barra —
      era a causa real do "horas cortadas" reportado. Com a barra
      isolada num track de altura fixa, o resto da coluna cresce por
      conteúdo normal (auto), sem disputa nenhuma. */
.species-chart-bars {
    display: flex;
    align-items: flex-end;
    gap: 18px;
    overflow-x: auto;
    padding-bottom: 6px; /* respiro pra scrollbar não colar na barra mais curta */
}
.species-chart-col {
    flex: none;
    width: 76px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
}
.species-chart-track { width: 100%; height: 140px; display: flex; align-items: flex-end; justify-content: center; }
.species-chart-bar { width: 100%; max-width: 52px; border-radius: 8px 8px 0 0; min-height: 4px; opacity: 0.85; transition: opacity 0.15s ease; }
.species-chart-col:hover .species-chart-bar { opacity: 1; }
/* display:block (não inline, o padrão de <span>) é OBRIGATÓRIO pro
   white-space:nowrap + overflow:hidden + text-overflow:ellipsis abaixo
   realmente cortarem o texto — num <span> inline puro essas 3
   propriedades são ignoradas pelo navegador, o texto vazava pra fora da
   coluna (largura fixa 76px) e invadia a coluna vizinha, cortando feio
   e desalinhando a linha inteira visualmente. width:100% (não
   max-width) trava exatamente na largura da coluna (.species-chart-col
   já tem width:76px), garantindo que os 3 elementos (valor/nome/
   contagem) fiquem sempre alinhados entre si. */
.species-chart-value { display: block; width: 100%; font-family: 'Bebas Neue', sans-serif; font-size: 20px; letter-spacing: 0.5px; color: #F8DCC0; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.species-chart-name { display: block; width: 100%; font-family: 'Poppins', sans-serif; font-size: 11px; color: #F8DCC0; opacity: 0.65; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.species-chart-count { display: flex; align-items: center; justify-content: center; gap: 3px; width: 100%; font-family: 'Poppins', sans-serif; font-size: 10px; opacity: 0.45; }
.species-chart-count i[data-lucide] { width: 10px; height: 10px; flex: none; }
@media (max-width: 480px) { .species-chart-track { height: 110px; } .species-chart-bars { gap: 14px; } .species-chart-col { width: 64px; } .species-chart-bar { max-width: 40px; } }

/* Tooltip do nome completo da espécie (species-chart-tooltip.js) —
   position:fixed de propósito, NÃO position:absolute dentro da coluna:
   .species-chart-bars rola horizontalmente (overflow-x:auto), e um
   tooltip position:absolute ali dentro seria cortado pela própria área
   de rolagem ao tentar "flutuar" acima da barra. data-tooltip="" no
   HTML (não title="") é o texto mostrado (nome completo + horas +
   jogadores) — de propósito SEM title="" junto: os dois ao mesmo tempo
   mostravam 2 balões sobrepostos (o nativo do navegador por cima do
   nosso), confirmado ao vivo pelo dono. */
.species-chart-tooltip-fixed {
    position: fixed;
    display: none;
    background: #131314;
    border: 1px solid rgba(220, 161, 94, 0.35);
    border-radius: 8px;
    padding: 6px 10px;
    font-family: 'Poppins', sans-serif;
    font-size: 12px;
    color: #F8DCC0;
    white-space: nowrap;
    pointer-events: none;
    z-index: 9999;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);
}

/* SCROLLBAR CUSTOMIZADA (Para não quebrar o visual premium) — height
   além de width: alguns elementos (ex: .species-chart-bars acima) rolam
   HORIZONTAL, e o webkit usa a dimensão "height" pra essa barra.
   scrollbar-width/scrollbar-color logo abaixo é o equivalente padrão
   (Firefox) — sem isso o Firefox ignorava as regras ::-webkit-* acima
   e mostrava a barra nativa do sistema, quebrando o visual só nesse
   navegador. */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
    background: rgba(248, 220, 192, 0.1);
    border-radius: 10px;
}
:root { scrollbar-width: thin; scrollbar-color: rgba(248, 220, 192, 0.1) transparent; }

.staff-info {
text-align: center;
}

.staff-info .name {
    font-family: var(--font-head);
    font-size: 1.2rem;
    margin-bottom: 8px;
    display: block;
}

/* Cargo: Fundo vermelho centralizado */
.staff-info .role {
    background: var(--surface); /* O seu vermelho/terracota */
    color: #FFF;
    font-size: 0.7rem;
    padding: 4px 20px;
    border-radius: 20px;
    display: inline-block;
    text-transform: uppercase;
    font-weight: bold;
    letter-spacing: 1px;
}

/* Link Sair: Centralizado e com respiro */
.logout-link {
    font-size: 0.6rem;
    text-transform: uppercase;
    opacity: 0.3;
    letter-spacing: 2px;
    margin-top: 5px;
    text-decoration: none;
    color: var(--text-primary);
    transition: 0.3s;
}

.logout-link:hover {
    opacity: 1;
}

/* --- GRÁFICO PREMIM COM EFEITO DE CORTE (O VERDADEIRO FIGMA) --- */
/* 1. O CARD EXTERNO (O container que corta) */
.premium-card-graph-container {
    position: relative;
    background: none;
    width: 150px; /* Largura do card */
    height: 160px; /* Altura do card */
    border-radius: 15px; /* As bordas arredondadas que você pediu */
    overflow: hidden; /* O SEGREDO: Corta tudo que sair daqui */
    display: flex;
    align-items: center;
    justify-content: center;
}

/* 2. O GRÁFICO (O elemento que vaza) */
.premium-graph-inner {
  background: none;
    position: absolute;
    /* Fazemos o container ser maior do que o card para vazar */
    width: 220px; 
    height: 250px;
    top: -28px; /* Centralizamos o container maior */
    left: -9px;
    transform: rotate(54deg); /* Faz o progresso começar no topo */
}

/* Estilo dos Arcos */
.premium-circle-bg {
    fill: none;
    stroke: #1f1d20; /* Trilho escuro */
    stroke-width: 16;
}

.premium-circle-34 {
    fill: none;
    stroke: #F8DCC0; /* Trilho escuro */
    stroke-width: 17;
    filter: blur(0px); /* Desfoca o próprio círculo */
    transform: translate(-0,3px, -0,3px);
}

.premium-circle-shadow {
    fill: none;
    stroke: #000000; /* Trilho escuro */
    stroke-width: 18;
    filter: blur(3px); /* Desfoca o próprio círculo */
    transform: translate(5px, -1px);
}

.premium-circle-progress {
    fill: none;
    stroke: var(--accent); /* Seu dourado --accent */
    stroke-width: 16;
}

/* 3. O TEXTO CENTRAL (Sempre visível) */
.premium-graph-label-container {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    z-index: 10; /* Garante que fica em cima do arco */
    padding: 20px;
    pointer-events: none; /* Garante que cliques passam pro SVG */
    transform: translate(25px, 20px);
}

.premium-graph-title {
    font-family: var(--font-body);
    color: var(--text-primary);
    font-size: 0.78rem;
    opacity: 0.8;
    margin-bottom: 0px;
}

.premium-graph-value {
    font-family: var(--font-head);
    color: var(--text-primary);
    font-size: 1.3rem;
    letter-spacing: 1px;
}
/*MANAGE STAFF: Estilo do Card de Gerenciamento (O card que aparece quando clica em "Gerenciar") */
/* Estilo dos Inputs com Ícone Lateral (Design da Imagem) */
.input-container-premium {
    display: flex;
    align-items: center;
    position: relative;
    background: #1F1D20;
    /* Borda dourada sólida (Figma "TextFieldWeb" completo, pedido do
       dono 2026-09-10) — a primeira versão desta borda (tracejado roxo
       #8A38F5, 5px) veio de um recorte que só trazia a MOLDURA DA
       PRANCHETA do Figma (o frame que agrupa os 6 estados de exemplo,
       não o componente em si); o componente de verdade, revelado
       quando o Figma completo foi colado, é essa borda dourada sólida
       com raio 10px — mesma cor/raio que .role-picker-bar já usava
       (que por coincidência já estava certo desde o início). */
    border: 1px solid #DCA15E;
    border-radius: 10px;
    overflow: hidden;
    margin-bottom: 15px;
    /* Trava o campo num tamanho razoável — sem isso o dropdown de cargo/
       canal fica enorme em telas muito largas, indo de ponta a ponta do
       card; cada campo continua do tamanho que precisa, só não estica
       além disso. */
    max-width: 480px;
    min-height: 50px;
    /* Glow "pra fora" em repouso (mesma fórmula dual do resto do site:
       .tp-btn, cards) — vira sombra afundada (inset) só durante o foco,
       ver :focus-within logo abaixo. */
    box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5), 10px 10px 20px rgba(0, 0, 0, 0.5), -10px -10px 20px rgba(0, 0, 0, 0.5);
}
.input-container-premium:focus-within {
    box-shadow: inset 5px 5px 15.4px rgba(0, 0, 0, 0.61);
}
/* Respiro entre o <label> do campo (ex: "Strike (Temporário)") e a caixa
   logo abaixo. Sibling adjacente pega qualquer label seguido de
   .input-container-premium/.banner-picker, sem precisar editar margem em
   cada página que usa esse padrão. */
label + .input-container-premium,
label + .banner-picker { margin-top: 8px; }

/* Mesmo respiro pro modo select-único do seletor de cargo
   (.role-picker-bar) — achado real (auditoria de consistência visual,
   2026-09-16, gameserver.ejs): .role-picker-bar só tem margin-bottom
   próprio (15px), sem margin-top nenhum, então label/p direto antes dele
   ficava colado (Regra nº1). O modo chips (.role-picker) já tinha
   margin-top:8px embutido na própria classe, por isso não precisava
   entrar aqui. */
label + .role-picker-bar,
p + .role-picker-bar { margin-top: 8px; }

/* Mesma ideia, mas pro parágrafo de DESCRIÇÃO (texto explicativo acima do
   label, ex: "Tem autoridade para aprovar...") quando ele é o elemento
   direto antes de um dropdown/caixa de texto/anexo de arquivo — 2px em
   todas as páginas que usam esse padrão. */
p + .input-container-premium,
p + .banner-picker { margin-top: 2px; }

/* Cargos selecionados (role-picker) direto depois de um parágrafo de
   descrição — separação MAIOR que os outros campos acima, em Equipe de
   Moderação/Supervisão de moderacao.ejs (único lugar onde .role-picker
   vem logo depois de um <p>; em events.ejs vem depois de <label>, cai
   direto no margin-top:8px próprio de .role-picker, sem passar por esta
   regra). */
p + .role-picker { margin-top: 16px; }

/* A caixinha dourada do ícone — quadrada, preenche a barra inteira
   (já era o comportamento real, só a cor/traço do ícone precisavam de
   ajuste, ver comentário completo na rodada de Campos de Texto).
   Traço mais grosso (stroke-width 3, era o padrão 2 do lucide) — mais
   fácil de ver no tamanho pequeno do ícone. border-radius/overflow
   PRÓPRIOS (2026-09-10, fix do dropdown que "parou de funcionar"): antes
   o cantinho arredondado do lado esquerdo vinha só do overflow:hidden do
   .input-container-premium/.role-picker-bar por fora — mas esse mesmo
   overflow:hidden também cortava (invisível, sem erro nenhum) o popup
   .tp-custom-select-list, que é position:absolute DENTRO desse mesmo
   container. Só isso já resolvia pro popup, mas deixar o icon-box
   independente do clip do pai é mais seguro (não depende mais de nenhum
   ancestral ter overflow:hidden pra continuar parecendo certo). */
.icon-box {
    background: #DCA15E; /* titan-gold */
    width: 45px;
    /* align-self:stretch (não height:45px fixo) — 2026-09-11, achado do
       dono: "a caixa com ícone não está preenchendo a caixa de texto",
       acontecia em qualquer container que renderizasse com altura MAIOR
       que os 45px (min-height:50px é só um PISO, não um teto — qualquer
       coisa que empurre o container pra mais alto que isso deixava uma
       tarja escura sobrando em cima/embaixo do quadrado dourado fixo).
       Com stretch, o ícone acompanha a altura de VERDADE do container,
       sempre "preenchendo a barra inteira" (comentário original já dizia
       isso, a implementação é que não garantia). */
    align-self: stretch;
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #131314;
    font-size: 1.2rem;
    border-radius: 10px 0 0 10px;
    overflow: hidden;
}
.icon-box svg { stroke-width: 3; }
/* Exceção: dentro de textarea (até 240px de altura, ver .has-textarea
   abaixo) o ícone tem que continuar um quadrado 45x45 fixo no topo, não
   esticar virando uma barra dourada gigante do tamanho do texto todo. */
.input-container-premium.has-textarea .icon-box { align-self: flex-start; height: 45px; }

.input-premium-field {
    background: transparent;
    border: none;
    padding: 0 15px;
    color: #F8DCC0;
    font-family: 'Poppins', sans-serif;
    font-weight: 600;
    width: 100%;
    outline: none;
    font-size: 0.9rem;
}
/* Placeholder cinza-escuro / texto digitado sempre creme (nunca uma cor
   de destaque separada) — mesma regra confirmada em todo o site: a cor
   do texto é sempre #F8DCC0, só a opacidade/tom muda por estado. */
.input-premium-field::placeholder { color: #3E3D38; font-weight: 600; opacity: 1; }
/* Lista de opções do <select> — sem isso fica com fundo branco e texto
   amarelo, diferente do dropdown de "adicionar cargo" que já é escuro;
   aqui os dois usam o mesmo fundo escuro + texto creme, e o padding
   evita que a letra fique colada na borda da lista. */
.input-premium-field option { background: #1F1D20; color: #F8DCC0; padding: 8px 12px; }

/* <textarea> reaproveitando o mesmo campo (mensagens do Report-Chat,
   personalização — ver reports.ejs) — herda a base de .input-premium-
   field acima, só ajusta o que é específico de textarea: padding-top MAIOR
   que os outros 3 lados (18px em vez de 15px evita que o texto cole na
   linha de cima, dada a fonte/line-height usada), altura mínima maior
   (caixa um pouco mais alta), fonte (textarea não herda font-family
   sozinho em todo navegador) e resize só vertical (o padrão do browser é
   nas duas direções, quebra o cantinho arredondado do container ao
   esticar pra largura). O .input-container-premium.has-textarea (classe
   própria no HTML, em vez de :has() por compatibilidade) vira
   align-items:flex-start pra a icon-box ficar no topo, não flutuando no
   centro vertical do textarea inteiro. field-sizing:content + max-height
   (pedido do dono): a caixa cresce sozinha até 240px, depois vira
   scroll interno (herda a barra fina/creme translúcido já global) em
   vez de continuar empurrando a página pra baixo — resize:vertical
   continua disponível pro dono ajustar na mão além disso. */
textarea.input-premium-field {
    min-height: 100px;
    max-height: 240px;
    field-sizing: content;
    padding: 18px 15px 14px;
    font-family: inherit;
    resize: vertical;
}
.input-container-premium.has-textarea { align-items: flex-start; }

/* <input type="file"> reaproveitando o mesmo campo (upload de imagem
   própria pros banners, tier Caçador) — o botão nativo do
   seletor de arquivo (::file-selector-button) não herda nada do resto do
   tema sozinho, então ganha estilo próprio aqui (cápsula dourada, mesma
   cor de .icon-box) em vez de ficar com a aparência crua do sistema
   operacional. */
/* -------- Upload com ícone-botão (auditoria de consistência visual,
   2026-09-15) — padrão fixo pra qualquer caixa de subir arquivo do site:
   .input-container-premium vira um <label> (clique em qualquer parte,
   inclusive no ícone, abre o seletor — comportamento nativo de <label> +
   <input> associado); .tp-file-hidden esconde o <input type="file"> de
   verdade sem tirar ele da árvore; o texto do campo (nome do arquivo) é
   controlado por JS, ver public/js/upload-preview.js. Substitui o
   <input type="file"> nativo com ::file-selector-button dentro da caixa
   (regras logo abaixo, mantidas só pra páginas ainda não migradas). -------- */
.tp-file-hidden { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.tp-upload-field { display: flex; flex-direction: column; }
.tp-upload-preview { width: 96px; height: 96px; border-radius: 10px; background-color: #1F1D20; border: 1px solid rgba(220, 161, 94, 0.25); background-size: cover; background-position: center; margin-bottom: 8px; }
.input-premium-field[type="file"] { padding: 8px 15px; cursor: pointer; }
.input-premium-field[type="file"]::file-selector-button {
    margin-right: 12px;
    padding: 6px 14px;
    border: none;
    border-radius: 6px;
    background: #DCA15E;
    color: #131314;
    font-family: 'Poppins', sans-serif;
    font-weight: 600;
    font-size: 0.8rem;
    cursor: pointer;
    transition: background 0.15s ease;
}
.input-premium-field[type="file"]::file-selector-button:hover { background: #F8DCC0; }

/* Galeria de escolha de banner — dá no site a mesma personalização de
   imagem que já existe no /config personalizar do Discord: lá é um
   <select> de texto por limitação do próprio Discord;
   aqui o site pode mostrar a prévia de cada opção). Cada opção é um
   <label> com um <input type="radio"> escondido — a seleção usa só CSS
   (:checked), sem precisar de JS. Mesmas opções/nomes de
   ConfigSystem.STRIKE_BANNER_OPTIONS/UNSTRIKE_BANNER_OPTIONS (dashboard.js
   GET /moderacao/:guildID), fonte única de verdade com o Discord. */
.banner-picker { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 8px; }
.banner-picker-option {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 150px;
    cursor: pointer;
}
.banner-picker-option input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}
.banner-picker-thumb {
    box-sizing: border-box;
    aspect-ratio: 600 / 138;
    border-radius: 10px;
    background-color: #131314;
    background-size: cover;
    background-position: center;
    border: 2px solid rgba(220, 161, 94, 0.25);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.banner-picker-option:hover .banner-picker-thumb { border-color: rgba(220, 161, 94, 0.6); }
.banner-picker-option input:checked + .banner-picker-thumb {
    border-color: #DCA15E;
    box-shadow: 0 0 0 2px rgba(220, 161, 94, 0.35);
}
.banner-picker-option input:focus-visible + .banner-picker-thumb { outline: 2px solid #DCA15E; outline-offset: 2px; }
/* Variante quadrada — avatar/emblema de perfil (/perfil) não são banners
   largos como Strike/Unstrike, ficam melhor 1:1. Plano de fundo continua
   com a proporção larga padrão (mesma cara de banner). */
.banner-picker-thumb.is-square { aspect-ratio: 1 / 1; }
.banner-picker-option.is-narrow { width: 90px; }
.banner-picker-label {
    font-family: 'Poppins', sans-serif;
    font-size: 11px;
    color: #F8DCC0;
    opacity: 0.7;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ===================== NÍVEIS DE PUNIÇÃO =====================
   Editor de níveis customizados do /strike, portado do painel Discord
   /config punishments (ver src/systems/core/configSystem.js
   refreshPointsPanel) — cada nível vira uma linha (.tp-list-row, padrão
   de lista unificado do site, ver logo abaixo) com ícone de severidade +
   nome + meta de pontos/duração/ação + ações de Editar/Deletar/Exigir-
   Dispensar Aprovação. Criar/Editar usam <details> (mesmo padrão sem-JS
   de .toc-group em documentacao.ejs) pra abrir um formulário compacto
   sem precisar de JS — reaproveita .input-container-premium/.input-
   premium-field pra cada campo em vez de inventar um novo estilo de
   input. */
.level-approval-badge { font-family: 'Poppins', sans-serif; font-size: 11px; font-weight: 600; }
.level-approval-badge.is-required { color: #A5FFA1; }
.level-approval-badge.is-not-required { color: #A89986; }

/* ===================== LINHA DE LISTA PADRÃO (.tp-list-row) =====================
   Pedido do dono, 2026-09-10: "a lista de transações tem um design
   perfeito, use ela como base pra um padrão pra toda e qualquer lista do
   site". Generaliza o .tx-row original (partials/transaction-history-
   list.ejs, removido de lá — a classe agora mora aqui, compartilhada) em
   ícone quadrado 32x32 + corpo (label/descrição opcional/meta) + ações
   opcionais à direita (.tp-list-row-actions, ausente = linha só de
   leitura como o histórico de transações original).

   Escopo confirmado com o dono: só listas de LINHA (Níveis de Punição,
   Buffs, Sincronizar Cargos, Webhooks, Lista de Jogadores, Staff Online/
   Offline, Reports, Histórico do Perfil, erros/checks de dev-
   servidores) — as GRADES de card com thumbnail (.loja-item da Loja/
   Inventário, .pool-item das páginas /dev) ficam de fora de propósito,
   são vitrine visual, não lista de dado, formato incompatível. */
.tp-list { display: flex; flex-direction: column; gap: 10px; }
.tp-list-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    padding: 12px 14px;
    background: #131314;
    border: 1px solid rgba(220, 161, 94, 0.2);
    border-radius: 12px;
}
.tp-list-row-icon {
    flex: none;
    width: 32px;
    height: 32px;
    border-radius: 8px;
    background: rgba(220, 161, 94, 0.12);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #DCA15E;
}
.tp-list-row-icon i, .tp-list-row-icon img { width: 16px; height: 16px; }
/* Variante com foto de verdade (ícone real do servidor) em vez de ícone
   Lucide pequeno — a imagem preenche a caixa toda (mesmo tamanho físico
   32x32, só sem a "margem" do ícone centralizado). */
.tp-list-row-icon.has-photo { overflow: hidden; }
.tp-list-row-icon.has-photo img { width: 100%; height: 100%; object-fit: cover; }
/* Variantes de cor — substituem o ponto colorido solto que cada lista
   (severidade de punição, status de staff online) reinventava do zero;
   aqui é a MESMA caixinha de ícone, só a cor muda (fundo 12%/ícone
   sólido, mesma fórmula do dourado padrão). */
.tp-list-row-icon.is-ok { background: rgba(165, 255, 161, 0.12); color: #A5FFA1; }
.tp-list-row-icon.is-warn { background: rgba(226, 193, 104, 0.12); color: #E2C168; }
.tp-list-row-icon.is-bad { background: rgba(226, 146, 78, 0.12); color: #E2924E; }
.tp-list-row-icon.is-danger { background: rgba(255, 78, 59, 0.12); color: #FF4E3B; }
.tp-list-row-icon.is-muted { background: rgba(168, 153, 134, 0.16); color: #A89986; }
.tp-list-row-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1 1 auto; }
.tp-list-row-label { font-family: 'Poppins', sans-serif; font-weight: 600; font-size: 13px; color: #F8DCC0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Variante pra rótulo que pode ser bem longo (ex: padrão regex do Filtro
   de Palavras) — quebra em várias linhas dentro da própria coluna do
   corpo em vez de cortar com "...", sem estourar pra cima dos botões de
   ação (que ficam numa coluna flex separada, tp-list-row-actions). */
.tp-list-row-label.is-wrap { white-space: normal; overflow: visible; text-overflow: unset; word-break: break-word; }
.tp-list-row-desc { font-family: 'Poppins', sans-serif; font-size: 12px; opacity: 0.75; color: #F8DCC0; word-break: break-word; }
.tp-list-row-meta { display: flex; flex-wrap: wrap; gap: 12px; font-family: 'Poppins', sans-serif; font-size: 11px; opacity: 0.5; color: #F8DCC0; margin-top: 2px; }
.tp-list-row-meta span { display: inline-flex; align-items: center; gap: 4px; }
.tp-list-row-meta i { width: 12px; height: 12px; }
/* A regra acima (.tp-list-row-meta span) dá display:inline-flex pra
   QUALQUER <span> filho, inclusive os pares data-i18n-pt/data-i18n-en
   aninhados aqui dentro — especificidade (classe+elemento) maior que a
   regra global de idioma no topo do arquivo (só atributo), então os
   DOIS idiomas apareciam juntos (ex: badge "Regex" duplicado — "Regex
   Regex" — no Filtro de Palavras). Reforça a regra de idioma só dentro
   deste container, com especificidade maior que a regra de display acima. */
.tp-list-row-meta [data-i18n-en] { display: none; }
html[data-lang="en"] .tp-list-row-meta [data-i18n-pt] { display: none; }
html[data-lang="en"] .tp-list-row-meta [data-i18n-en] { display: initial; }
/* Ações (Editar/Deletar/badges) — ausente numa linha só de leitura (ex:
   Histórico de Transações). flex:none pra não disputar espaço com o
   corpo, wrap pra não estourar a linha em telas estreitas. */
.tp-list-row-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; flex: none; margin-left: auto; }
/* Variante empilhada — linha que precisa mostrar conteúdo EXTRA embaixo
   do cabeçalho (ex: Buffs: cabeçalho ícone+nome+deletar, depois a lista
   de atributos do buff, depois o form de adicionar atributo). O
   cabeçalho interno vira um .tp-list-row-head "flush" (mesmo
   icon+body+actions, sem fundo/borda própria — quem desenha o
   fundo/borda é o .tp-list-row.is-stack de fora). */
.tp-list-row.is-stack { flex-direction: column; align-items: stretch; gap: 12px; }
.tp-list-row-head { display: flex; align-items: center; gap: 12px; }
/* Lista de chips dentro de uma linha .is-stack (ex: espécies de uma
   categoria) — align-items/align-content:flex-start é necessário porque
   esse container vira item de uma linha do grid do editor de 2 colunas
   quando aberto (ver regras .tp-list-row.is-stack:has(...) acima), que
   estica pra bater a altura da coluna de edição do lado; sem isso os
   chips (sem altura própria) esticariam junto (flex padrão é stretch)
   em vez de manter o tamanho natural de sempre. */
.lj-category-species { display: flex; flex-wrap: wrap; align-items: flex-start; align-content: flex-start; gap: 6px; }
/* Variante de alerta — linha que precisa se destacar como "algo deu
   errado" (ex: erros recentes de um servidor em dev-servidores.ejs), em
   vez do fundo/borda neutros padrão. */
.tp-list-row.is-alert { background: rgba(255, 87, 87, 0.06); border-color: rgba(255, 87, 87, 0.2); }
/* [hidden] precisa de especificidade MAIOR que .tp-list-row (display:flex
   acima) pra realmente esconder a linha — o atributo/propriedade IDL
   `hidden` sozinho perde pro display explícito de uma classe de autor
   (usado por filtros de lista client-side, ex: perfil-historico.ejs). */
.tp-list-row[hidden] { display: none; }

/* Botão pequeno em cápsula (Editar/Deletar/Exigir-Dispensar Aprovação/
   Criar Nível/Resetar Padrão) — mesma família visual do .role-chip (borda
   dourada, fundo escuro), só que clicável (<button> ou <summary> de
   <details>) em vez de estático. */
.btn-chip {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 14px;
    background: #1F1D20;
    border: 1px solid #DCA15E;
    border-radius: 147.5px;
    font-family: 'Poppins', sans-serif;
    font-weight: 600;
    font-size: 12px;
    color: #F8DCC0;
    cursor: pointer;
    transition: background 0.15s ease, transform 0.1s ease;
}
summary.btn-chip { list-style: none; }
summary.btn-chip::-webkit-details-marker { display: none; }
summary.btn-chip::marker { content: ''; }
.btn-chip:hover { background: #803E30; }
.btn-chip-success { border-color: #A5FFA1; color: #A5FFA1; }
.btn-chip-success:hover { background: rgba(165, 255, 161, 0.12); }
.btn-chip-danger { border-color: #FF4E3B; color: #FF4E3B; }
.btn-chip-danger:hover { background: rgba(255, 78, 59, 0.12); }

/* Formulário compacto de Criar/Editar nível — abre dentro de um <details>
   (fecha por padrão), grid responsivo pros 5 campos do nível. Margem-top
   condicional a [open] SÓ dentro de .tp-list-row-actions — sem esse
   escopo, mesmo FECHADO o <details> ficava margin-top:4px mais alto que
   os irmãos flex (badge/botões, sem margem nenhuma); como um flex item é
   seu próprio contexto de formatação de bloco, essa margem não colapsa
   com nada e passa a contar na altura do próprio item, descentralizando
   o align-items:center da linha. Só quando o details ABRE (editando)
   essa margem faz sentido, pra separar o summary do formulário logo
   abaixo. margin-bottom no summary aberto continua GERAL (Criar e
   Editar) — diferente do margin-top, não tem conflito nenhum com outra
   margem.

   Escopar pra .tp-list-row-actions também evita um conflito de
   especificidade: o <details> standalone de "+ Criar Nível" (fora de
   .tp-list-row-actions, com sua PRÓPRIA margem Tailwind mt-3=12px pra
   afastar da lista de níveis acima) usa a MESMA classe
   .level-form-details do "Editar" — uma regra [open] genérica não
   escopada (2 seletores, especificidade maior que .mt-3) sobrescreveria
   o mt-3 ao abrir, encolhendo a margem de 12px pra 4px. */
/* SESSÕES DE CONFIGURAÇÃO RECOLHÍVEIS (gameserver.ejs) — <details> no
   lugar do <div>/<form> que era o card antes (.titan-card-premium
   continua na MESMA tag, só muda o elemento), <summary> vira o
   cabeçalho clicável (título + chevron). Fechado, <details> some com
   tudo que não for <summary> sozinho (comportamento nativo do
   elemento) — não precisa de JS nem de regra CSS extra pra esconder o
   corpo. Diferente de .level-form-details acima (recolhível DENTRO de
   um card já visível, ex: "Editar"/"Ver Game.ini") — aqui o <details>
   É o card inteiro. */
/* display:flex/align-items/justify-content/gap centralizados AQUI (não
   como classe Tailwind solta no <summary> de cada sessão em
   gameserver.ejs) de propósito: sem isso o <summary> usava flex-wrap,
   que jogava o chevron pra uma linha NOVA (embaixo, colado à esquerda)
   sempre que o título quebrava em 2 linhas no mobile — o chevron
   "sumia" do canto da caixa. align-items:flex-start (não center) +
   .section-title com flex:1/min-width:0 (permite o título quebrar
   PRÓPRIO texto sem forçar a linha do flex a quebrar) mantém o chevron
   sempre fixo no canto superior direito, título de 1 ou 2 linhas. */
.config-section > summary {
    cursor: pointer;
    list-style: none;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 4px;
    /* Linha divisória sutil embaixo do cabeçalho (Regra nº2 do rascunho,
       Figma Frame 12028/Line 12) — nunca tinha sido aplicada de verdade
       (achado 2026-09-17, dono reportou "falta o separador abaixo do
       título da sessão" em Logs/Aparência/Conexão). No rascunho é uma
       <div class="config-section-divider"> própria com margin:5px 0; aqui
       vira border-bottom direto no summary (mesmo resultado visual, sem
       precisar mexer no HTML de cada página) — o padding já existente
       (16px fechado / 24px aberto, ver .config-section[open] > summary
       abaixo) já faz o papel do respiro antes da linha. Visível tanto
       fechado quanto aberto, igual o rascunho pede. */
    border-bottom: 1px solid rgba(255, 255, 255, 0.14);
}
.config-section > summary .section-title { flex: 1 1 auto; min-width: 0; margin: 0; }
.config-section > summary::-webkit-details-marker { display: none; }
.config-section-chevron { width: 20px; height: 20px; flex: none; color: #DCA15E; opacity: 0.85; transition: transform 0.2s ease; }
.config-section[open] > summary .config-section-chevron { transform: rotate(180deg); }

/* Rascunho "Padrão de Tipografia" ponto (4) — extraído do Figma (Frame
   22/20/19), descartando width/height/order/flex-grow de auto-layout
   (canvas, não o componente). Fechada: SEM fundo/moldura, cabeçalho de
   2 linhas (título curto + subtítulo descritivo) solto na página — troca
   o antigo <h2 class="section-title"> de 1 linha só. Aberta: os MESMOS
   valores visuais de .titan-card-premium (radial-gradient/20px/sombra),
   só que condicionados a [open] em vez de fixos na classe — antes disso
   o card aparecia mesmo fechado (a classe titan-card-premium ficava
   direto na tag <details>), por isso ela sai do HTML de cada seção e as
   propriedades visuais se mudam pra cá. */
.config-section[open] {
    background: radial-gradient(225.25% 94.36% at 0% 86.37%, #111111 0%, #1F1D20 57.07%, #29272A 91.53%);
    box-shadow: 0.5px -0.5px 0.5px #F8DCC0, -25px 47px 68.1px rgba(0, 0, 0, 0.74);
    border-radius: 20px;
    display: flex;
    padding: 40px;
    width: 100%;
    box-sizing: border-box;
}
@media (max-width: 767px) {
    .config-section[open] { padding: 18px; }
}
.config-section[open] > summary { padding: 0 0 24px; }
/* ACHADO REAL, GRAVE (auditoria de consistência visual, 2026-09-17,
   dono reportou "itens colados, margens sem padrão, sem separadores" —
   verificado com um teste isolado, sem Tailwind, sem JS nenhum, só CSS
   puro): o Chrome tem um bug real de layout onde `gap` NÃO é aplicado
   entre os filhos de um <details> quando ele vira flex container via CSS
   do autor (display:flex por fora, não nativo do elemento) — mesmo o
   `getComputedStyle` mostrando `gap: 24px` corretamente, o espaço
   renderizado entre os filhos fica ZERO. Reproduzido em isolamento com 3
   variações (classe do Tailwind, classe pura, seletor por atributo tipo
   `details[open]`) — as 3 falham do mesmo jeito; um <div> comum com o
   MESMO `display:flex` + `gap` funciona normalmente. Ou seja: TODO
   `<details class="... gap-4|gap-6 config-section">` do site inteiro
   (Cargos/Logs/Aparência em moderacao.ejs/gameserver.ejs/events.ejs/
   lojajogo.ejs/reports.ejs/dev-*.ejs) está com o espaçamento entre os
   filhos de primeiro nível quebrado desde sempre, silenciosamente — não
   é uma regressão desta rodada, é a causa raiz de boa parte do "colado"
   reportado. Corrigido SEM mexer em nenhum arquivo .ejs (o bug é só
   entre <details> e `gap`, nunca aparece em <div>/<form> comuns já
   usados pra tudo dentro de cada sub-bloco) — troca `gap` por
   `margin-top` no filho, direto aqui, cobrindo as 2 variantes de gap
   (gap-4=16px, gap-6=24px) já usadas no site. `summary` nunca entra
   nessa conta (já tem seu próprio padding-bottom:24px acima, cobrindo o
   espaço entre o cabeçalho e o 1º bloco de conteúdo) — a regra de baixo
   zera a margem só do filho que vem logo depois dele, pra não somar os
   dois espaçamentos. */
.config-section[open].gap-4 > * + * { margin-top: 16px; }
.config-section[open].gap-6 > * + * { margin-top: 24px; }
.config-section[open].gap-4 > summary + *,
.config-section[open].gap-6 > summary + * { margin-top: 0; }
/* Separador dourado entre sessões FECHADAS empilhadas (Cargos + Logs +
   Frequência dentro de Game Server, por ex.) — REMOVIDO (achado real,
   2026-09-17, dono reportou "2 separadores ao ter sessões fechadas").
   Desde que .config-section > summary ganhou seu próprio border-bottom
   branco sutil (ver regra acima, cobre título FECHADO e ABERTO), esta
   linha dourada ficava DUPLICADA embaixo de toda sessão fechada — o
   próprio rascunho já avisava sobre esse risco exato ("ao aplicar a
   Regra nº2 numa página, REMOVER aquele CSS de separador ali, senão fica
   linha duplicada"), aviso que não segui da primeira vez por cautela.
   O border-bottom do summary sozinho já marca onde uma sessão fechada
   termina e a próxima começa — não precisa mais desta regra. */
.config-section-head { display: flex; flex-direction: column; gap: 6px; min-width: 0; flex: 1 1 auto; }
.config-section-title {
    font-family: 'Poppins', sans-serif;
    font-weight: 400;
    font-size: 22px;
    letter-spacing: 0.3em;
    color: #DCA15E;
    text-transform: uppercase;
    margin: 0;
}
.config-section-subtitle {
    font-family: 'Poppins', sans-serif;
    font-weight: 400;
    font-size: 13px;
    letter-spacing: 0.2em;
    color: #F8DCC0;
    opacity: 0.8;
    text-transform: uppercase;
}
@media (max-width: 480px) {
    .config-section-title { font-size: 18px; letter-spacing: 0.15em; }
    .config-section-subtitle { letter-spacing: 0.1em; }
}
/* Sessão ANINHADA dentro de outra .config-section (ex: "Ver Lista de
   Jogadores" dentro do card "Jogadores" de gameserver.ejs) — abre sem
   virar um card dentro do card, mesmo cabeçalho de 2 linhas mas sem o
   fundo/sombra/padding do card padrão. */
.config-section-nested[open] {
    background: none;
    box-shadow: none;
    border-radius: 0;
    padding: 0;
    display: block;
}
/* ACHADO REAL (dono reportou, 2026-09-17: "campo de busca e botão de
   filtro estão encostados no separador") — a regra genérica de baixo
   (.config-section[open].gap-4 > summary + *) zera a margem do 1º filho
   depois do <summary>, partindo do princípio de que o padding-bottom:24px
   do summary (regra "> summary" acima) já dá respiro suficiente ANTES da
   linha divisória. Isso é verdade pro espaço ENTRE o título e a linha,
   mas não sobra NADA depois da linha até o próximo conteúdo — medido de
   verdade com getBoundingClientRect (gap = 0px exato) antes de mexer
   aqui. Some nos outros .config-section porque o 1º elemento de dentro
   costuma ter padding/margem própria; aqui o toolbar de busca+filtro é
   colado (.tp-list-toolbar só tem margin-bottom, nunca margin-top),
   então fica visualmente grudado na linha. Mesma especificidade da regra
   de baixo (2 classes+1 atributo + summary+*) — vem DEPOIS no arquivo,
   então vence no empate. */
.config-section-nested[open] > summary + [data-players-ajax-root] { margin-top: 16px; }

.level-form-details { width: 100%; }
/* Era escopado em .level-card-actions — essa classe não existe mais no
   HTML (migrada pra .tp-list-row-actions, padrão de lista unificado,
   2026-09-10); mesmo motivo original continua valendo (ver comentário
   completo de level-form-grid abaixo sobre o conflito de especificidade
   com o <details> "+ Criar Nível" standalone). */
.tp-list-row-actions .level-form-details[open] { margin-top: 4px; }
.level-form-details[open] > summary { margin-bottom: 10px; }
.level-form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 4px 16px;
}
/* ACHADO REAL (teste responsivo, 2026-09-17, largura mobile real 400px):
   6 forms.level-form-grid pelo site (Sincronizar Cargos, Webhooks etc.)
   têm style="min-width:280px" inline — pensado pra não deixar o painel de
   edição ficar espremido demais em colunas largas do desktop, mas em
   telas de celular (bem menos que 280px de sobra depois do padding do
   card + coluna do ícone) esse mínimo força a página inteira a abrir mão
   e ficar mais larga que a viewport (documentElement.clientWidth media
   500px reais contra os 400px pedidos) — corta conteúdo à direita.
   !important necessário pra vencer o style="" inline (nenhuma regra de
   classe externa vence atributo inline sem isso). */
@media (max-width: 640px) {
    .level-form-grid { min-width: 0 !important; }
}
/* form.level-form-grid (qualquer form "Criar"/"Editar" com .level-form-fields
   + .level-form-actions como filhos diretos, ex: "+ Sincronizar" em
   gameserver.ejs, "+ Criar Nível"/"+ Criar Buff"/"+ Criar Filtro" em
   moderacao.ejs) — bug real encontrado na auditoria de consistência visual
   (2026-09-16): sem isto, o display:grid de .level-form-grid acima tratava
   .level-form-fields e .level-form-actions como 2 colunas lado a lado
   (auto-fit minmax(160px,1fr) com só 2 filhos = 2 colunas largas), jogando
   o botão Salvar longe à direita com um vão enorme em vez de ficar logo
   abaixo dos campos — só os forms de edição DENTRO de .tp-list-row-actions
   tinham esse empilhamento corrigido (regra abaixo, escopada só ali); os
   forms "Criar" standalone (fora de qualquer .tp-list-row) nunca tinham
   essa correção. .level-form-grid como <div> (painel de Busca+Filtro) não
   é afetado — o seletor é escopado à tag <form>. */
form.level-form-grid { display: flex; flex-direction: column; }
.level-form-grid label:not(.input-container-premium) { font-size: 11px; opacity: 0.6; display: block; margin-bottom: 4px; }
.level-form-grid .input-container-premium { max-width: none; margin-bottom: 8px; }
/* Sem .icon-box do lado (diferente do resto do site), a altura da caixa
   vem só do padding do próprio input — padding:0 15px (só lateral)
   deixava o texto colado em cima/embaixo, daí o padding vertical extra
   aqui — só neste grid, não em .input-premium-field geral (que já tem
   sua própria altura definida por .icon-box no resto do dashboard). */
.level-form-grid .input-premium-field { padding: 11px 16px; }
/* Texto de exemplo (ex: "10m, 1h, 3d — vazio = perm.") movido pra baixo
   do campo em vez de dentro do <label>: o label de Duração era o único
   com 2 linhas, empurrando aquele input mais pra baixo que os campos
   vizinhos na mesma linha do grid (label mais curto = todos os inputs
   alinham pelo topo). */
.level-form-grid .level-form-hint { display: block; font-size: 10px; opacity: 0.4; margin-top: 2px; margin-bottom: 4px; }
/* Caixas de campo com mesma altura quando lado a lado na mesma linha do
   grid (auditoria de consistência visual, 2026-09-15, pedido do dono:
   "caixas de edição/seleção devem sempre ter a mesma altura e largura
   quando em conjunto próximas uma da outra") — sem isso um <select>
   nativo pode renderizar com altura ligeiramente diferente de um
   <input> de texto na mesma linha. */
.level-form-grid .input-container-premium { height: 42px; min-height: 0; box-sizing: border-box; }
/* Conteúdo do painel de edição sempre alinhado à direita (2026-09-15,
   pedido do dono: "tudo nos painéis de edição deve ficar alinhado a
   direita") — o botão Editar/X do <summary> já fica na borda direita
   (ver .tp-list-row-actions .level-form-details abaixo); os botões de
   ação (Excluir/Salvar/Aprovação) seguem o mesmo alinhamento. */
.level-form-actions { display: flex; align-items: flex-end; justify-content: flex-end; gap: 10px; margin-top: 14px; }
/* Mobile: item #17 da auditoria de responsividade 2026-09-27 — "botões
   na mesma linha, em vertical sempre que possível, sem diminuir eles de
   forma diferente" — sem flex-wrap, 2-3 botões (Excluir/Cancelar/Salvar,
   o painel de edição mais comum do site) num painel estreito de mobile
   podiam ficar espremidos (flex-shrink:1 é o padrão de qualquer item
   flex, e .tp-btn não tem largura mínima própria) em vez de trocar de
   linha. flex-direction:column (não só flex-wrap:wrap) garante 1 botão
   por linha sempre — nunca um par assimétrico numa 2ª linha — mantendo
   align-items:flex-end (não stretch) pra continuar batendo a regra já
   existente "painel de edição sempre alinhado à direita" (cada botão no
   próprio tamanho natural, só empilhado). */
@media (max-width: 640px) {
    .level-form-actions { flex-direction: column; align-items: flex-end; }
}
/* Campos do form num bloco separado da linha de botões — precisa disto
   sempre que o <form> vira flex-column (editor de linha em 2 colunas,
   ver regras .tp-list-row-actions abaixo), senão Nome/Severidade/
   Pontos/Duração perderiam o layout em grade e empilhariam um por um. */
.level-form-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 4px 16px; }
/* Ícone-botão só-ícone (círculo, mesmo sistema de sombra dupla do
   .tp-btn, tom neutro marrom sempre — sem variante de ação). O seletor
   combinado abaixo também vira o botão "Editar" (<summary>) quando o
   editor de linha (Punições/Categorias/Webhooks) está ABERTO — círculo-X
   é EXCLUSIVO do Editar dos editores de linha, nenhum outro botão usa
   (ver .tp-toggle-closed/.tp-toggle-open abaixo pro HTML de 2 estados). */
.tp-icon-btn,
.level-form-details[open] > summary.tp-btn.is-edit:has(.tp-toggle-open) {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border-radius: 16px;
    background: #2A2A2A;
    border: 1px solid #803E30;
    box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5), -5px -5px 10px rgba(0, 0, 0, 0.7);
    color: #F8DCC0;
    cursor: pointer;
    transition: background 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease, color 0.12s ease;
}
.tp-icon-btn svg,
.level-form-details[open] > summary.tp-btn.is-edit:has(.tp-toggle-open) svg { display: block; width: 14px; height: 14px; flex: none; stroke-width: 3; }
.tp-icon-btn:hover,
.level-form-details[open] > summary.tp-btn.is-edit:has(.tp-toggle-open):hover { background: #803E30; border-color: #F8DCC0; box-shadow: -5px -5px 10px rgba(0,0,0,0.5), 5px 5px 10px rgba(0,0,0,0.5), 10px 10px 20px rgba(0,0,0,0.5), -10px -10px 20px rgba(0,0,0,0.5); }
.tp-icon-btn:active,
.level-form-details[open] > summary.tp-btn.is-edit:has(.tp-toggle-open):active { background: #4B2427; border-color: #803E30; box-shadow: 1px 1px 2px rgba(0,0,0,0.5), -1px -1px 2px rgba(0,0,0,0.5), inset 0px 8px 7.8px rgba(0,0,0,0.59); }
.tp-icon-btn:disabled { background: #2A2A2A !important; border-color: #3E3D38 !important; color: #3E3D38 !important; box-shadow: 1px 1px 2px rgba(0,0,0,0.5), -1px -1px 2px rgba(0,0,0,0.5) !important; cursor: not-allowed; }
/* 2 estados de texto do botão Editar (fechado: "Editar" / aberto: X) —
   inline-flex nos dois pra centralizar ícone+texto igual qualquer outro
   .tp-btn com ícone. */
.tp-toggle-closed, .tp-toggle-open { display: inline-flex; align-items: center; gap: 9px; }
.level-form-details:not([open]) > summary .tp-toggle-open { display: none; }
.level-form-details[open] > summary .tp-toggle-closed { display: none; }

/* -------- Editor de linha em 2 colunas lado a lado (auditoria de
   consistência visual, 2026-09-15, pedido do dono usando Punições como
   referência: "dividindo ao meio a lista... painel de edição
   perfeitamente alinhado" ao conteúdo). Ao abrir o editor de qualquer
   .tp-list-row com edição embutida (Punições, Categorias, Webhooks), a
   linha vira 2 colunas em vez de empurrar o painel pra uma 2ª linha
   embaixo: conteúdo à esquerda, painel de edição à direita, esticado até
   bater a MESMA altura da coluna esquerda. Cai pra 1 coluna em telas
   estreitas. -------- */
.tp-list-row:not(.is-stack):has(> .tp-list-row-actions > .level-form-details[open]) {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) minmax(0, 1fr);
    align-items: stretch;
    gap: 16px 28px;
}
.tp-list-row:not(.is-stack):has(> .tp-list-row-actions > .level-form-details[open]) > .tp-list-row-icon { grid-column: 1; grid-row: 1; }
.tp-list-row:not(.is-stack):has(> .tp-list-row-actions > .level-form-details[open]) > .tp-list-row-body { grid-column: 2; grid-row: 1; }
.tp-list-row:not(.is-stack):has(> .tp-list-row-actions > .level-form-details[open]) > .tp-list-row-preview { grid-column: 1 / 3; grid-row: 2; }
.tp-list-row:not(.is-stack):has(> .tp-list-row-actions > .level-form-details[open]) > .tp-list-row-actions { grid-column: 3; grid-row: 1 / span 2; }
/* Prévia ao vivo (Regra nº7) — filho opcional de .tp-list-row, só visível
   com o editor aberto e só na coluna esquerda, embaixo do conteúdo da
   linha (pedido do dono: "a prévia pode ficar na coluna da esquerda,
   abaixo do item da lista"). */
.tp-list-row-preview { display: none; }
.tp-list-row:has(> .tp-list-row-actions > .level-form-details[open]) > .tp-list-row-preview { display: block; }
/* Escopado com :has(> .lj-category-species) de propósito — só a linha de
   Categorias tem essa estrutura (cabeçalho + chips de espécie); outras
   linhas .is-stack com um <details> embutido (ex: Buffs, "+ Adicionar
   Atributo" por atributo) NÃO têm esse filho e por isso ficam de fora
   deste grid específico até ganharem seu próprio exemplo confirmado —
   sem isso, o grid tentaria posicionar um filho que não existe e
   deixaria o conteúdo de Buffs em auto-placement indefinido. */
.tp-list-row.is-stack:has(> .lj-category-species):has(.tp-list-row-actions .level-form-details[open]) {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: stretch;
    gap: 12px 28px;
}
.tp-list-row.is-stack:has(> .lj-category-species):has(.tp-list-row-actions .level-form-details[open]) > .tp-list-row-head { grid-column: 1; grid-row: 1; }
.tp-list-row.is-stack:has(> .lj-category-species):has(.tp-list-row-actions .level-form-details[open]) > .lj-category-species { grid-column: 1; grid-row: 2; }
.tp-list-row.is-stack:has(> .lj-category-species):has(.tp-list-row-actions .level-form-details[open]) > .tp-list-row-actions { grid-column: 2; grid-row: 1 / span 2; }
.tp-list-row:has(> .tp-list-row-actions > .level-form-details[open]) > .tp-list-row-actions,
.tp-list-row.is-stack:has(> .lj-category-species):has(.tp-list-row-actions .level-form-details[open]) > .tp-list-row-actions { margin-left: 0; }
/* Excluir (e qualquer outro botão solto irmão do <details>, ex: "Testar"
   em Webhooks) sempre visível ao lado de Editar na linha FECHADA, some
   quando o editor abre — o botão de exclusão/ação "de verdade" mora
   dentro do painel. */
.tp-list-row-actions:has(> details[open]) > .tp-btn,
.tp-list-row-actions:has(> details[open]) > form { display: none; }
/* Botões do painel (Excluir/Salvar/toggle) na BASE da coluna, à direita —
   pedido do dono: "botões devem ficar sempre na base com exceção do x" +
   "tudo nos painéis de edição deve ficar alinhado a direita". flex-grow
   em vez de height:100% (mais robusto, não depende de altura resolvida
   em cascata através do <details>). */
.tp-list-row-actions:has(> details[open]) { display: flex; flex-direction: column; align-items: stretch; }
.tp-list-row-actions > details[open] { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.tp-list-row-actions > details[open] > summary { flex: none; align-self: flex-end; }
.tp-list-row-actions > details[open] > form.level-form-grid { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }
.tp-list-row-actions > details[open] > form.level-form-grid > .level-form-actions { margin-top: auto; padding-top: 16px; }
.tp-list-row-actions .level-form-details { text-align: right; }
@media (max-width: 640px) {
    .tp-list-row:not(.is-stack):has(> .tp-list-row-actions > .level-form-details[open]),
    .tp-list-row.is-stack:has(.tp-list-row-actions .level-form-details[open]) {
        grid-template-columns: 1fr;
    }
    /* ACHADO REAL (auditoria de consistência visual, 2026-09-17, teste em
       largura mobile real 400px): o bloco acima só reseta
       grid-template-columns do PAI pra 1 coluna, mas nunca resetava o
       grid-column/grid-row explícito dos FILHOS (linhas 1161-1164 acima —
       ícone/corpo/prévia/ações continuavam fixados nas colunas 1/2/3 do
       layout desktop). Grid cria colunas IMPLÍCITAS pra satisfazer um
       grid-column:3 mesmo dentro de um grid-template-columns:1fr — essas
       colunas implícitas não têm largura reservada, então o painel de
       Editar (Sincronizar Cargos, Webhooks, Punições — qualquer
       .tp-list-row com editor embutido) vazava pra fora da tela no
       celular. Cada filho precisa do próprio reset pra coluna 1, empilhado
       na ordem natural do DOM (ícone → corpo → prévia → ações). */
    .tp-list-row:not(.is-stack):has(> .tp-list-row-actions > .level-form-details[open]) > .tp-list-row-icon,
    .tp-list-row:not(.is-stack):has(> .tp-list-row-actions > .level-form-details[open]) > .tp-list-row-body,
    .tp-list-row:not(.is-stack):has(> .tp-list-row-actions > .level-form-details[open]) > .tp-list-row-preview,
    .tp-list-row:not(.is-stack):has(> .tp-list-row-actions > .level-form-details[open]) > .tp-list-row-actions {
        grid-column: 1;
        grid-row: auto;
    }
    .tp-list-row.is-stack:has(.tp-list-row-actions .level-form-details[open]) > .lj-category-species { grid-row: 2; }
    .tp-list-row.is-stack:has(.tp-list-row-actions .level-form-details[open]) > .tp-list-row-actions { grid-column: 1; grid-row: 3; }
}
/* Upload dentro de um editor de 2 colunas (ex: Título/Emblema/Missão em
   /dev) usa <label class="input-container-premium"> como wrapper
   clicável — sem o :not() abaixo, essa regra de label pequeno (pensada
   só pros <label> de campo comuns) também pegava o label-wrapper de
   upload, quebrando o align-self:stretch do ícone lá dentro. */
.level-form-grid label:not(.input-container-premium) { font-size: 11px; opacity: 0.6; display: block; margin-bottom: 4px; }

/* -------- Barra de busca + filtro padrão (.tp-list-toolbar/
   .tp-filter-panel), auditoria de consistência visual 2026-09-14/15 —
   pensada pra qualquer lista do site precisar de busca+filtro (Histórico
   de Compras, Suas Denúncias, Histórico do Perfil, Reportes). Busca
   sozinha na esquerda, botão Filtro totalmente à direita; sem "Aplicar
   Filtros" — mudar um campo já filtra a lista ao vivo, só "Limpar"
   continua, dentro do painel. -------- */
.tp-list-toolbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
.level-form-details.tp-filter-panel { width: auto; margin-left: auto; }
.tp-filter-panel { text-align: right; }
.tp-filter-panel .level-form-grid { width: 320px; max-width: 100%; margin-top: 10px; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
.tp-list-toolbar:has(.tp-filter-panel[open]) { display: grid; grid-template-columns: 1fr auto; align-items: start; gap: 16px 20px; }
.tp-list-toolbar:has(.tp-filter-panel[open]) > .tp-filter-panel { grid-column: 2; margin-left: 0; }
@media (max-width: 640px) {
    .tp-list-toolbar:has(.tp-filter-panel[open]) { grid-template-columns: 1fr; }
}

/* -------- Prévia estilo Discord (.tp-discord-mock) — mockup fiel de como
   um card sai no Discord (bolha de mensagem + Container V2 com faixa de
   cor), usado pela prévia ao vivo de Punições (Regra nº7: "mostre
   exatamente como aparecia na punição no discord"). max-width:360px fixo
   sempre, mesmo em coluna larga — não estica pra não colar no painel de
   edição do lado (achado 2026-09-15). -------- */
.tp-discord-mock { max-width: 360px; background: #313338; border-radius: 8px; padding: 14px; margin-top: 8px; font-family: 'gg sans', 'Segoe UI', Helvetica, Arial, sans-serif; }
.tp-discord-header { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.tp-discord-avatar { width: 40px; height: 40px; border-radius: 50%; background: linear-gradient(135deg, #5865F2, #2A2A2A); flex: none; display: flex; align-items: center; justify-content: center; font-family: 'Tilt Warp', sans-serif; font-size: 13px; color: #fff; }
.tp-discord-name-row { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.tp-discord-name { font-weight: 600; font-size: 14px; color: #F2F3F5; }
.tp-discord-bot-tag { background: #5865F2; color: #fff; font-size: 9px; font-weight: 700; padding: 1px 4px; border-radius: 3px; line-height: 1.3; }
.tp-discord-time { font-size: 11px; color: #949BA4; }
.tp-discord-container { display: flex; background: #2B2D31; border-radius: 8px; overflow: hidden; }
.tp-discord-accent { width: 4px; flex: none; transition: background 0.2s ease; }
.tp-discord-body { flex: 1 1 auto; min-width: 0; padding: 12px; display: flex; flex-direction: column; gap: 10px; }
.tp-preview-banner { aspect-ratio: 600 / 138; border-radius: 6px; background-size: cover; background-position: center; display: flex; align-items: center; justify-content: center; transition: background 0.2s ease; }
.tp-preview-banner-title { font-family: 'Tilt Warp', sans-serif; font-weight: 400; font-size: 15px; letter-spacing: 0.1em; text-transform: uppercase; transition: color 0.2s ease; }
.tp-preview-footer { margin: 0; padding-top: 8px; border-top: 1px solid rgba(255,255,255,0.06); font-size: 11px; color: #949BA4; }
.tp-discord-user-section { display: flex; gap: 10px; align-items: flex-start; }
.tp-discord-user-thumb { width: 44px; height: 44px; border-radius: 50%; flex: none; background-size: cover; background-position: center; background-color: #1E1F22; }
.tp-discord-user-text { font-size: 13px; line-height: 1.5; color: #DBDEE1; }
.tp-discord-user-text .heading { display: block; font-weight: 700; color: #F2F3F5; font-size: 14px; }
.tp-discord-sep { border: none; border-top: 1px solid rgba(255,255,255,0.08); margin: 0; }
.tp-discord-code { background: #1E1F22; border-radius: 4px; padding: 8px 10px; font-family: Consolas, 'Courier New', monospace; font-size: 12.5px; color: #DBDEE1; white-space: pre-wrap; margin: 0; }

/* Botão Salvar Específico da Imagem */
.btn-salvar-final {
    background: #252326;
    border: 1px solid #803E30;
    color: #F8DCC0;
    font-family: 'Tilt Warp', cursive;
    padding: 12px 60px;
    border-radius: 15px;
    text-transform: uppercase;
    letter-spacing: 2px;
    cursor: pointer;
    transition: all 0.3s;
    box-shadow: 0px 5px 15px rgba(0,0,0,0.4);
}

.btn-salvar-final:hover {
    background: #803E30;
    transform: scale(1.05);
}

/* ==================== .tp-btn — padrão-base de botão (Figma "Button",
   Primary/Hover/Pressed/Disabled) confirmado no rascunho "Auditoria de
   Botões" (2026-09-11) — marrom universal (#2A2A2A/#803E30) que TODO
   botão do site vai usar por padrão, com variantes de acento por ação:
   .is-edit (dourado fixo), .is-delete (vermelho fixo), .is-save.is-dirty
   (verde #A5FFA1 SÓ quando há edição pendente — resto do tempo é o
   marrom padrão, não uma cor fixa do Salvar), .is-buy/.is-buy.is-hunt
   (compacto, mesmo CSS que .loja-jogo-buy-form/.loja-perso-buy-form já
   usam, só reescrito nesta sintaxe). .is-save agora é o botão "Salvar"
   de TODA página de configuração do dashboard (rollout completo
   2026-09-13, pedido do dono: "todos os botões de salvar... escrito só
   Salvar e sem ícone" — antes era .btn-salvar-final com "Salvar
   Alterações"/ícone, um rollout gradual página por página; ver
   gameserver.ejs/moderacao.ejs/reports.ejs/events.ejs/
   pf-personalizacao-form.ejs). .btn-salvar-final sobrevive só nos 2
   botões de conversão de moeda da Loja ("Converter em Marks/Ossos",
   texto/proposta diferentes de um Salvar de formulário — ver loja.ejs).
   is-dirty é ligada automaticamente em QUALQUER form da página via
   web/public/js/save-dirty.js (delegado no document, sem precisar de id
   nem script por página) — sem esse script incluído, o botão fica
   sempre no marrom parado (.tp-btn puro), que já é o comportamento
   correto de repouso. */
.tp-btn {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    padding: 9px 24px;
    height: 39px;
    border-radius: 15px;
    font-family: 'Poppins', sans-serif;
    font-weight: 600;
    font-size: 14px;
    cursor: pointer;
    transition: background 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease, color 0.12s ease;
    background: #2A2A2A;
    border: 1px solid #803E30;
    color: #F8DCC0;
    box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5), -5px -5px 10px rgba(0, 0, 0, 0.7);
}
.tp-btn svg, .tp-btn i { width: 16px; height: 16px; flex: none; }
.tp-btn:hover { background: #803E30; border-color: #F8DCC0; box-shadow: -5px -5px 10px rgba(0, 0, 0, 0.5), 5px 5px 10px rgba(0, 0, 0, 0.5), 10px 10px 20px rgba(0, 0, 0, 0.5), -10px -10px 20px rgba(0, 0, 0, 0.5); }
.tp-btn:active { background: #4B2427; border-color: #803E30; box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5), -1px -1px 2px rgba(0, 0, 0, 0.5), inset 0px 8px 7.8px rgba(0, 0, 0, 0.59); }

.tp-btn.is-edit { border-color: #DCA15E; }
.tp-btn.is-edit:hover { background: #DCA15E; color: #131314; }
.tp-btn.is-edit:active { background: #6E4E23; border-color: #DCA15E; color: #F8DCC0; }

.tp-btn.is-delete { border-color: #FF4E3B; }
.tp-btn.is-delete:hover { background: #FF4E3B; }
.tp-btn.is-delete:active { background: #5A1811; border-color: #FF4E3B; }

/* Salvar SÓ vira verde com .is-dirty (algo digitado/alterado ainda não
   salvo) — sem ela é um .tp-btn marrom igual qualquer outro. 3 classes
   > 1, então ganha do .tp-btn base sem precisar de !important. */
.tp-btn.is-save.is-dirty { border-color: #A5FFA1; }
.tp-btn.is-save.is-dirty:hover { background: #A5FFA1; color: #131314; }
.tp-btn.is-save.is-dirty:active { background: #4C754A; border-color: #A5FFA1; color: #F8DCC0; }

.tp-btn:disabled { background: #2A2A2A !important; border-color: #3E3D38 !important; color: #3E3D38 !important; box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5), -1px -1px 2px rgba(0, 0, 0, 0.5) !important; cursor: not-allowed; }
.tp-btn:disabled svg, .tp-btn:disabled i { opacity: 0.5; }

/* Comprar — mesmo CSS de .loja-jogo-buy-form/.loja-perso-buy-form
   (partials/loja-item-styles.ejs), só na sintaxe .tp-btn; não substitui
   os originais (ainda não adotado lá), só documenta a família pronta
   pra quando for a vez daquelas páginas. */
.tp-btn.is-buy {
    background: radial-gradient(225.25% 94.36% at 0% 86.37%, #111111 0%, #1F1D20 57.07%, #29272A 91.53%);
    border-color: #F8DCC0;
    color: #F8DCC0;
    height: auto;
    min-width: 92px;
    padding: 4px 10px;
    font-size: 10px;
    gap: 5px;
}
.tp-btn.is-buy svg, .tp-btn.is-buy i { width: 12px; height: 12px; }
.tp-btn.is-buy:active { background: #4B2427; border-color: #DCA15E; color: #DCA15E; }
.tp-btn.is-buy.is-hunt { border-color: #803E30; color: #FF4E3B; }
.tp-btn.is-buy.is-hunt:hover { border-color: #FF4E3B; }

/* --- Botão Primário (Figma: componente "Button", modos Primary/Hover/Pressed/Disabled) ---
   Uso: <button class="btn-primary"> ou <a class="btn-primary">, com <span class="btn-primary-icon">
   opcional antes do texto. Estado disabled: atributo "disabled" (button) ou classe "is-disabled" (a). */
.btn-primary {
    box-sizing: border-box;
    display: inline-flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
    padding: 5px 20px;
    gap: 10px;
    min-width: 232px;
    height: 39px;
    background: var(--bg-card);
    border: 1px solid var(--surface);
    border-radius: 15px;
    box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5), -5px -5px 10px rgba(0, 0, 0, 0.7);
    font-family: var(--font-body);
    font-weight: 600;
    font-size: 20px;
    line-height: 30px;
    color: var(--text-primary);
    text-decoration: none;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

.btn-primary-icon {
    width: var(--btn-icon-size);
    height: var(--btn-icon-size);
    border-radius: 50%;
    background: currentColor;
    flex: none;
}

.btn-primary:hover:not(:disabled):not(.is-disabled) {
    background: var(--surface);
    border-color: var(--text-primary);
    box-shadow: -5px -5px 10px rgba(0, 0, 0, 0.5), 5px 5px 10px rgba(0, 0, 0, 0.5),
                10px 10px 20px rgba(0, 0, 0, 0.5), -10px -10px 20px rgba(0, 0, 0, 0.5);
}

.btn-primary:active:not(:disabled):not(.is-disabled),
.btn-primary.is-pressed {
    background: var(--surface-hover);
    border-color: var(--surface);
    box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5), -1px -1px 2px rgba(0, 0, 0, 0.5),
                inset 0px 8px 7.8px rgba(0, 0, 0, 0.59);
}

.btn-primary:disabled,
.btn-primary.is-disabled {
    background: var(--bg-card);
    border-color: #3E3D38;
    color: #3E3D38;
    box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5), -1px -1px 2px rgba(0, 0, 0, 0.5);
    cursor: not-allowed;
    pointer-events: none;
}

/* --- Botão Primário, tamanho MOBILE (Figma: "ButtonMobile"/"Subtitle
   Mobile") — mesmas cores/bordas/box-shadow por estado de cima
   (Primary/Hover/Pressed/Disabled já batem 1:1 com o
   componente web, não precisam de override nenhum), só encolhe padding
   vertical/tipografia/ícone. min-width/height viram automáticos (largura
   de verdade no Figma, 78x21, veio do texto "Button" de exemplo — um
   valor fixo aqui cortaria rótulos mais longos já em uso no site, ex:
   "Assinar via Ko-fi"); a largura REAL sempre foi content-driven aqui
   (padding + line-height), então "solta" o min-width de 232px do
   desktop é o suficiente pra chegar num resultado visualmente equivalente
   sem arriscar cortar texto. */
@media (max-width: 767px) {
    .btn-primary {
        min-width: 0;
        height: auto;
        font-weight: 300;
        font-size: var(--fs-body-sm);
        line-height: 21px;
    }
}

/* --- Outline Chip (Figma: "Frame 12007" etc, STAFF ONLINE/OFFLINE) ---
   Cartão sem preenchimento, só contorno colorido + ícone + título/subtítulo
   — usado pela lista de staff (ingame-pulse.ejs) E pelo quadro de alerta
   (moderacao.ejs), mesmo visual nos dois lugares de propósito (pedido do
   dono). Verde (--online) = ok/online, vermelho (--offline) = precisa de
   atenção/offline. */
.outline-chip {
    --chip-color: #A5FFA1;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 20px;
    border: 1px solid var(--chip-color);
    border-radius: 10px;
    background: none;
}
.outline-chip.is-bad { --chip-color: #FF4E3B; }
.outline-chip-icon { width: 34px; height: 34px; flex: none; color: var(--chip-color); }
.outline-chip-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.outline-chip-headline {
    font-family: 'Tilt Warp', cursive;
    font-size: clamp(12px, 1.8vw, 18px);
    line-height: 1.2;
    color: #DCA15E;
    text-transform: uppercase;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.outline-chip-subtitle {
    font-family: 'Poppins', sans-serif;
    font-weight: 600;
    font-size: 12px;
    color: #F8DCC0;
    opacity: 0.85;
}
/* Variante "grande" (Figma: "Frame 22" do quadro de alerta, 802x138,
   padding:30px, gap:8px, ícone 50x50). Fonte ~10pt menor que o valor
   exato do Figma (32px/20px) — no tamanho exato do Figma o texto ficava
   grande demais pra caixa. Sem max-width: fica fill no eixo horizontal,
   preenchendo o corpo principal igual aos outros cards
   (.titan-card-premium), em vez de travar nos 802px originais do
   Figma. */
.outline-chip.is-lg {
    gap: 8px;
    padding: 30px;
    width: 100%;
}
.outline-chip.is-lg .outline-chip-icon { width: 50px; height: 50px; }
.outline-chip.is-lg .outline-chip-headline { font-size: clamp(14px, 2.2vw, 22px); }

/* Conteúdo "apagado" com a tag de tier por cima (pedido do dono,
   2026-09-08) — usado em gráficos/análises que ficam visíveis pra
   qualquer tier mas só mostram dado de verdade a partir do plano exigido
   (diferente do outline-chip acima, que é um AVISO ao lado do conteúdo
   real; aqui o próprio conteúdo fica visualmente bloqueado). A tag fica
   centralizada por cima via position:absolute — pointer-events:none no
   conteúdo evita cliques/hover em gráfico que não deveria funcionar
   (tooltip de espécie, etc). */
.tier-locked-wrap { position: relative; }
.tier-locked-wrap .tier-locked-content {
    opacity: 0.3;
    filter: grayscale(70%);
    pointer-events: none;
    user-select: none;
}
.tier-locked-wrap .tier-locked-badge {
    position: absolute;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    z-index: 2;
}

/* Trava por tier — padrão ÚNICO decidido 2026-09-15, substitui
   .tier-locked-wrap/.tier-locked-content/.tier-locked-badge acima E
   .pf-field-locked/.pf-lock-tag (perfil-personalizacao) — preto-e-branco
   DE VERDADE (grayscale 100%, não mais 70%) + desabilitada, aplicada por
   FUNÇÃO/CAMPO específico (nunca a sessão/card inteiro de uma vez). O
   selo de tier (.tp-info-badge) mora sempre junto do título da sessão ou
   do campo (ex: dentro do .tp-info-name-row), nunca mais solto por cima
   do conteúdo borrado como o .tier-locked-badge antigo fazia.
   ACHADO REAL (2026-09-16, verificado via screenshot antes de reportar
   como aplicado): esta classe já estava em uso em moderacao.ejs/
   reports.ejs desde a sessão anterior, mas a regra CSS nunca tinha sido
   criada de verdade aqui — o bloco ficava sem nenhum efeito visual,
   sessão "travada" continuava 100% normal e clicável. As páginas que já
   usam .tp-tier-locked no HTML passam a funcionar assim que este arquivo
   for publicado, sem precisar tocar nelas de novo. */
.tp-tier-locked { opacity: 0.35; filter: grayscale(100%); pointer-events: none; user-select: none; cursor: not-allowed; transition: opacity 0.2s ease, filter 0.2s ease; }
.tp-tier-locked * { pointer-events: none !important; cursor: not-allowed !important; }

/* ===================== CONFIGURAÇÕES =====================
   Configurações usa o visual simples padrão (.titan-card-premium/
   .input-container-premium, mesmo padrão de events.ejs) — o card-por-bloco
   exato do Figma (Moderação.txt) foi removido daqui. */

/* Seletor de cargo com suporte a MÚLTIPLOS valores — ver
   partials/role-picker.ejs. Visual PRÓPRIO (Figma "TextFieldWeb", pedido
   do dono 2026-09-10) — borda dourada SÓLIDA (#DCA15E) + fundo escuro,
   distinto do .input-container-premium genérico (borda tracejada roxa)
   usado pelo resto dos campos do site: seções de cargo/role ficam
   visualmente marcadas como sua própria categoria. margin-top separa os
   chips do texto/label que vem antes deles no form — sem isso ficam
   colados um no outro. */
.role-picker { display: flex; flex-direction: column; gap: 12px; width: 100%; margin-top: 8px; }
.role-picker-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.role-chip {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 6px 6px 14px;
    background: #1F1D20;
    border: 1px solid #DCA15E;
    border-radius: 10px;
    font-family: 'Poppins', sans-serif;
    font-weight: 600;
    font-size: 13px;
    color: #F8DCC0;
    max-width: 100%;
}
.role-chip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.role-chip-remove {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    flex: none;
    background: transparent;
    border: none;
    border-radius: 6px;
    color: #DCA15E;
    cursor: pointer;
    transition: background 0.12s ease, color 0.12s ease;
}
.role-chip-remove:hover { background: #803E30; color: #F8DCC0; }
.role-chip-remove i { width: 14px; height: 14px; }

/* Barra do próprio cargo — usada tanto no modo select único (limit<=1)
   quanto no select de "adicionar cargo" do modo chips (junto de
   .role-picker-add-bar abaixo). icon-box já é dourado (mesma cor de
   sempre), então só a borda/fundo/raio ficam definidos aqui; o texto do
   <select> reaproveita .input-premium-field (classe dupla no HTML) pra
   não duplicar aquele CSS. */
.role-picker-bar {
    display: flex;
    align-items: center;
    position: relative;
    background: #1F1D20;
    border: 1px solid #DCA15E;
    border-radius: 10px;
    overflow: hidden;
    max-width: 480px;
    min-height: 50px;
    /* Glow "pra fora" em repouso, igual .input-container-premium/.tp-btn
       — era sempre um inset fixo antes, diferente do resto dos campos
       de texto; agora só afunda (inset) durante o foco. */
    box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5), 10px 10px 20px rgba(0, 0, 0, 0.5), -10px -10px 20px rgba(0, 0, 0, 0.5);
    margin-bottom: 15px;
}
.role-picker-bar:focus-within {
    box-shadow: inset 5px 5px 15.4px rgba(0, 0, 0, 0.61);
}
.role-picker-select { flex: 1 1 auto; min-width: 0; }

.role-picker-row { display: flex; align-items: center; width: 100%; }
/* Modo chips: a MESMA barra acima (.role-picker-bar), só que sem o
   margin-bottom (fica sozinha na linha, sem outro campo embaixo) e
   crescendo pra ocupar o espaço disponível. */
.role-picker-row .role-picker-add-bar { flex: 1 1 auto; min-width: 0; margin-bottom: 0; }

.role-picker-limit {
    font-family: 'Poppins', sans-serif;
    font-weight: 400;
    font-size: 12px;
    color: #A89986;
}

/* ===== Dropdown 100% nosso (rascunho "Campos de Texto", 2026-09-10) =====
   Nenhum navegador deixa estilizar a lista de opções de um <select>
   nativo (fundo/borda/raio/divisor) — resolvido antes com .input-premium-
   field option, mas isso só troca a cor, o resto da moldura continua sendo
   desenhada pelo sistema operacional. Este bloco é a camada visual que
   substitui a lista de verdade: um botão-gatilho + <ul> popup, ligados ao
   <select> original (que fica no DOM, só escondido) por custom-select.js
   — ver esse arquivo pro porquê do <select> continuar existindo. O modo
   "adicionar cargo" do role-picker (clique já cria o chip, não usa
   <select> nenhum) usa a MESMA lista/gatilho aqui, ver role-picker.js. */
.tp-select-enhanced > select.input-premium-field { display: none; }
/* Sem isso o popup fica invisível/inclicável — .input-container-premium/
   .role-picker-bar têm overflow:hidden (pro cantinho do .icon-box, agora
   auto-suficiente, ver comentário lá) que cortava o
   .tp-custom-select-popup de propósito position:absolute aqui dentro. */
.tp-select-enhanced { overflow: visible; }

.tp-select-trigger {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    height: 100%;
    min-height: 50px;
    background: transparent;
    border: none;
    outline: none;
    padding: 0 15px;
    color: #F8DCC0;
    font-family: 'Poppins', sans-serif;
    font-weight: 600;
    font-size: 0.9rem;
    text-align: left;
    cursor: pointer;
}
.tp-select-trigger:disabled { cursor: not-allowed; opacity: 0.5; }
/* Seta substituindo a seta nativa do <select> (escondido) — mesma pista
   visual, cor dourada padrão do resto dos ícones. */
.tp-select-trigger::after {
    content: '';
    flex: none;
    width: 8px;
    height: 8px;
    border-right: 2px solid #DCA15E;
    border-bottom: 2px solid #DCA15E;
    transform: rotate(45deg);
    margin-top: -5px;
    transition: transform 0.15s ease;
}
.tp-select-trigger[aria-expanded="true"]::after { transform: rotate(-135deg); margin-top: 5px; }

/* Popup = moldura (posição/borda/sombra); .tp-custom-select-list vira um
   filho normal dela (era a própria posicionada antes de ter busca —
   agora o campo de texto precisa de um lugar FIXO no topo, fora da
   área que rola). Ver custom-select.js pro porquê da busca existir
   (pedido do dono, 2026-09-27). */
.tp-custom-select-popup {
    position: absolute;
    left: 0;
    right: 0;
    top: calc(100% + 8px);
    z-index: 40;
    background: #1F1D20;
    border: 1px solid #DCA15E;
    border-radius: 10px;
    box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5), 10px 10px 20px rgba(0, 0, 0, 0.5);
    overflow: hidden;
}
/* Variante do dropdown "Adicionar cargo/dinossauro" (role-picker.ejs/
   species-picker.ejs) — achado real, 2026-10-01: o popup absoluto acima
   é pensado pra um select isolado (flutua por CIMA do que vem depois,
   comportamento normal de dropdown); role-pickers costumam vir
   EMPILHADOS de perto uns dos outros na mesma sessão (até 3 em
   moderacao.ejs: Supervisor/Moderador/Menção de Report), então flutuar
   tampava o campo/contador seguinte de verdade, não só sobrepor visual
   sem nada embaixo. Mesma moldura/borda/sombra (herda tudo de
   .tp-custom-select-popup), só troca o posicionamento pra fluxo normal —
   empurra o que vem depois pra baixo em vez de cobrir. */
.tp-custom-select-popup-inline {
    position: static;
    margin-top: 8px;
}
.tp-custom-select-search {
    display: block;
    width: 100%;
    box-sizing: border-box;
    padding: 10px 14px;
    background: rgba(0, 0, 0, 0.2);
    border: none;
    border-bottom: 1px solid rgba(220, 161, 94, 0.3);
    color: #F8DCC0;
    font-family: 'Poppins', sans-serif;
    font-weight: 600;
    font-size: 0.85rem;
    outline: none;
}
.tp-custom-select-search::placeholder { color: #F8DCC0; opacity: 0.4; }
.tp-custom-select-list {
    margin: 0;
    padding: 6px;
    list-style: none;
    max-height: 260px;
    overflow-y: auto;
}
.tp-custom-select-list li {
    padding: 10px 12px;
    color: #F8DCC0;
    font-family: 'Poppins', sans-serif;
    font-weight: 600;
    font-size: 0.9rem;
    border-radius: 6px;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Divisor LEVE entre os itens — o contorno cheio fica só na moldura da
   caixa (regra confirmada pro site inteiro); entre itens de uma lista é
   sempre esta versão translúcida. :not([hidden]) ignora quem a busca
   escondeu — sem isso um item filtrado deixava a borda "encostada" no
   próximo item visível, uma linha fantasma sem nada acima dela. */
.tp-custom-select-list li:not([hidden]) ~ li:not([hidden]) { border-top: 1px solid rgba(220, 161, 94, 0.18); margin-top: 2px; padding-top: 12px; }
.tp-custom-select-list li:hover,
.tp-custom-select-list li[aria-selected="true"] { background: rgba(220, 161, 94, 0.18); }
.tp-custom-select-list li.is-disabled { opacity: 0.4; cursor: not-allowed; }
.tp-custom-select-list li.tp-custom-select-empty { color: #F8DCC0; opacity: 0.4; cursor: default; font-weight: 500; font-style: italic; }
.tp-custom-select-list li.tp-custom-select-empty:hover { background: none; }

/* Selo de tier (Figma: "user.icon") — marca seções exclusivas do plano
   Rastreador/Caçador em todo o site, ver partials/tier-badge.ejs. Nome em
   inglês ("Tracker"/"Hunter") de propósito, mesma convenção já usada em
   hero.ejs:572 (Free/Tracker/Hunter = nome internacional do tier).

   Migrado 2026-09-15 (auditoria de consistência visual) de .tier-badge
   (grande, 121x39, dourado=Rastreador/vermelho=Caçador) para este selo
   único e menor — mesmo raciocínio unificado usado por .tp-btn/.tp-list-row:
   1 componente compartilhado em vez de tamanhos/tons soltos por página. Base
   (sem modificador) = tom dourado (Rastreador/"Tracker"); .is-hunter = tom
   marrom/vermelho (Caçador/"Hunter") — inverte a base do antigo .tier-badge
   de propósito, já que o dourado é o mais comum nas páginas do site. */
.tp-info-badge {
    box-sizing: border-box;
    display: inline-flex;
    justify-content: center;
    align-items: center;
    padding: 0 10px;
    gap: 6px;
    height: 24px;
    background: linear-gradient(179.54deg, #A25E2D 47.59%, #DCA15E 99.6%);
    border: 3px solid #DCA15E;
    box-shadow: 0px 12px 18px 11px rgba(1, 2, 10, 0.45);
    border-radius: 147.5px;
    font-family: 'Poppins', sans-serif;
    font-weight: 400;
    font-size: 12px;
    line-height: 1;
    color: #F8DCC0;
    white-space: nowrap;
    flex: none;
    /* Sempre um <a href="/#premium"> agora (ver partials/tier-badge.ejs) —
       reseta o sublinhado/cursor padrão de link, já que o resto do selo
       (cor, fundo) já é definido acima. */
    text-decoration: none;
    cursor: pointer;
    transition: filter 0.15s ease;
}
.tp-info-badge:hover { filter: brightness(1.12); }
/* Variante "Hunter" (Caçador) — mesmo selo, tom marrom/vermelho em vez do
   dourado padrão de "Tracker" (Rastreador). Ver partials/tier-badge.ejs,
   parâmetro `tier`. */
.tp-info-badge.is-hunter {
    background: linear-gradient(179.54deg, #4B2427 47.59%, #803E30 99.6%);
    border-color: #803E30;
}

/* Descrição de cargo/canal (Figma Frame 12007) — ícone 50×50 + nome +
   emblema de tier (.tp-info-badge, só quando o cargo/canal exige tier) +
   texto explicativo, sempre DENTRO da sessão (Cargos/Logs), nunca um
   card à parte. Nome do cargo/canal em Tilt Warp 22px (não o Poppins
   20px do Figma nem 32px de um primeiro teste, desproporcionais perto
   do resto do texto) — mesma fonte de destaque já usada em títulos do
   site. Ícone é uso PONTUAL de assets/icons (imagem de verdade, nunca
   Lucide/SVG solto aqui) — ver regra de origem do ícone no rascunho. */
.tp-info-row { display: flex; align-items: center; gap: 20px; width: 100%; }
.tp-info-row + .tp-info-row { margin-top: 20px; }
.tp-info-icon { width: 50px; height: 50px; flex: none; object-fit: contain; }
.tp-info-body { display: flex; flex-direction: column; justify-content: center; align-items: flex-start; gap: 5px; flex: 1 1 auto; min-width: 0; }
.tp-info-name-row { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
.tp-info-name { font-family: 'Tilt Warp', 'Poppins', sans-serif; font-weight: 400; font-size: 22px; line-height: 1.2; letter-spacing: 0.02em; color: #F8DCC0; }
.tp-info-desc { font-family: 'Poppins', sans-serif; font-weight: 400; font-size: 13px; line-height: 1.5; color: #A89986; width: 100%; }
/* Campo logo abaixo da descrição de cargo/canal (Regra nº1 — nunca
   colado): bug real achado na auditoria de 2026-09-16 (gameserver.ejs,
   "Cargo de Registro") — .tp-info-row é um <div>, então nenhuma das
   regras "label + .role-picker-bar"/"p + .role-picker" acima (linhas
   556-572, pensadas pra <label>/<p>) pegava esse caso: o modo
   select-único (.role-picker-bar) ficava com 0px de margem, literalmente
   colado na descrição. Mesmo valor já usado em "p + .role-picker"
   (16px) — .tp-info-row É a descrição, mesmo papel. */
.tp-info-row + .role-picker,
.tp-info-row + .role-picker-bar,
.tp-info-row + .input-container-premium,
.tp-info-row + .banner-picker { margin-top: 16px; }

/* Overlay genérico (backdrop + cartão centralizado) — usado pro aviso de
   sucesso/falha ao salvar Configurações (ver
   partials/save-result-overlay.ejs), mesma receita já usada em
   web/views/hero.ejs pro aviso de "dashboard em desenvolvimento" (aquela
   cópia é local à hero.ejs/index.ejs, que têm <style> próprio e não usam
   este arquivo compartilhado — aqui é a versão pras páginas que ficam
   atrás do login, moderacao.ejs/events.ejs, que sim usam). Reaproveitável
   por qualquer outro aviso modal futuro do dashboard.  */
.dev-overlay {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: rgba(10, 9, 10, 0.85);
    backdrop-filter: blur(4px);
}
.dev-overlay-card {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    text-align: center;
    max-width: 420px;
    width: 100%;
    padding: 36px 28px;
    background: radial-gradient(225.25% 94.36% at 0% 86.37%, #111111 0%, #1F1D20 57.07%, #29272A 91.53%);
    border-radius: 20px;
    box-shadow: 0.5px -0.5px 0.5px #F8DCC0, -25px 47px 68.1px rgba(0, 0, 0, 0.74);
}
.dev-overlay-icon {
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 60px;
    height: 60px;
    flex: none;
    background: #2A2A2A;
    border: 2px solid #803E30;
    border-radius: 50%;
    color: #DCA15E;
}
.dev-overlay-icon i, .dev-overlay-icon svg { width: 28px; height: 28px; }
/* Variantes de cor pro resultado do save — mesmo verde/vermelho da
   paleta oficial do projeto (#A5FFA1/#FF4E3B), já usados em
   .btn-chip-success/.btn-chip-danger e .outline-chip/.outline-chip.is-bad. */
.dev-overlay-card.is-success .dev-overlay-icon { border-color: #A5FFA1; color: #A5FFA1; }
.dev-overlay-card.is-error .dev-overlay-icon { border-color: #FF4E3B; color: #FF4E3B; }
.dev-overlay-title {
    font-family: 'Tilt Warp', cursive;
    font-size: clamp(17px, 2.2vw, 22px);
    letter-spacing: 0.05em;
    color: #F8DCC0;
    text-transform: uppercase;
}
.dev-overlay-text {
    font-family: 'Poppins', sans-serif;
    font-size: 14px;
    line-height: 1.6;
    color: #F8DCC0;
    opacity: 0.85;
}

/* Par de botões (Fechar + ação, ex: "Ir ao inventário") — overlay de
   compra concluída na Loja de Personalização precisa de um botão extra
   além de Fechar, seguindo o padrão dos botões da sidebar. Receita
   idêntica a .tp-sidebar-btn
   (partials/sidebar-v2.ejs) copiada aqui em vez de reaproveitada
   direto — mesmo motivo de sempre nesta base (.loja-usar-form
   .btn-chip.btn-chip-success etc.): aquela classe só existe dentro do
   <style> da própria sidebar, e este parcial roda em várias páginas
   sem depender de qual outro parcial foi incluído junto. Só aparece
   quando o chamador passa actionHref (função opcional, todo o resto
   que já usa este parcial continua só com o botão Fechar de sempre,
   sem quebrar nada). */
.dev-overlay-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; width: 100%; }
.dev-overlay-btn {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    flex: 1 1 auto;
    min-width: 140px;
    height: 40px;
    padding: 5px 20px;
    background: #2A2A2A;
    border: 1px solid #803E30;
    box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5), -5px -5px 10px rgba(0, 0, 0, 0.7);
    border-radius: 14px;
    color: #F8DCC0;
    font-family: 'Poppins', sans-serif;
    font-weight: 600;
    font-size: 13px;
    text-decoration: none;
    cursor: pointer;
}
.dev-overlay-btn:hover { background: #803E30; border-color: #F8DCC0; }
.dev-overlay-btn:active {
    background: #4B2427;
    border-color: #803E30;
    box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5), -1px -1px 2px rgba(0, 0, 0, 0.5), inset 0px 8px 7.8px rgba(0, 0, 0, 0.59);
}
.dev-overlay-btn i, .dev-overlay-btn svg { width: 16px; height: 16px; flex: none; }

.outline-chip.is-lg .outline-chip-subtitle { font-size: clamp(12px, 1.4vw, 15px); opacity: 1; }

/* Modo visualização (cargo de equipe sem Administrator só visualiza, não
   edita) — atenuação visual dos
   formulários de EDIÇÃO enquanto public/js/dashboard-view-only-lock.js
   marca os campos como disabled de verdade. form[method="POST"] é a
   convenção de sempre pra "isto grava algo" nestas páginas (busca/
   paginação usam method="GET", ver partials/reports-list.ejs), então
   nunca esmaece uma busca por engano. */
body[data-view-only="true"] form[method="POST"] { opacity: 0.6; }

/* ===================== LISTA DE DENÚNCIAS (partials/reports-list.ejs) =====================
   Movida de reports.ejs pro style.css compartilhado — a partial passou a
   ser reaproveitada por uma segunda página (perfil-denuncias.ejs, "Suas
   Denúncias" — lista global filtrada por usuário em vez de por
   servidor), deixando de ser exclusiva de reports.ejs. O container do
   card virou .tp-list-row (2026-09-10, padrão de lista unificado) — só
   o badge de status/servidor continuam com classe própria abaixo. */
.report-status {
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 1px;
    background: var(--surface);
    border-radius: 20px;
    padding: 3px 12px;
    opacity: 0.85;
}
/* Selo de servidor por card — só aparece quando a lista mistura reports
   de vários servidores (showGuildBadge:true, ver reports-list.ejs). Nas
   páginas de 1 servidor só (reports.ejs) fica sempre desligado. Mostra
   logo + nome, não só o nome sozinho. */
.report-guild-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.65rem;
    color: #A89986;
    background: rgba(220, 161, 94, 0.1);
    border-radius: 20px;
    padding: 3px 10px 3px 3px;
}
.report-guild-badge img,
.report-guild-badge .report-guild-badge-fallback {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    object-fit: cover;
    flex: none;
}
.report-guild-badge .report-guild-badge-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    background: #4B2427;
    color: #DCA15E;
}
.report-guild-badge .report-guild-badge-fallback svg { width: 10px; height: 10px; }

/* Barra de busca (por ID de report ou usuário que abriu) + paginação das
   seções Abertos/Fechados. Campo de busca é .input-container-premium/
   .icon-box de verdade. Migrado 2026-09-15 (auditoria de consistência
   visual) de .report-search-form/.report-filter-details (próprias desta
   página) pro padrão compartilhado .tp-list-toolbar/.tp-filter-panel —
   ver definições mais abaixo neste arquivo; qualquer filtro (Servidor/
   Data/Staff) filtra ao vivo (auto-submit no onchange), sem botão
   "Aplicar Filtros". */
/* Paginação (Reports + Game Server) usa o botão PADRÃO do site
   (.tp-btn), não .btn-chip nem nada bespoke — "Anterior"/"Próxima" não
   tem significado especial (não é editar/salvar/excluir/comprar),
   então é exatamente o caso pro botão genérico confirmado na rodada
   de Botões. Primeira aplicação de verdade de .tp-btn no CSS real —
   base só (marrom, sem variante de ação), o resto dos 9 usos antigos
   segue pendente pra quando entrarmos na implementação completa. */
.report-pagination { display: flex; align-items: center; justify-content: center; gap: 16px; margin-top: 4px; }

.tp-btn {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    padding: 9px 24px;
    height: 39px;
    background: #2A2A2A;
    border: 1px solid #803E30;
    border-radius: 15px;
    box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5), -5px -5px 10px rgba(0, 0, 0, 0.7);
    color: #F8DCC0;
    font-family: 'Poppins', sans-serif;
    font-weight: 600;
    font-size: 14px;
    cursor: pointer;
    text-decoration: none;
    transition: background 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease, color 0.12s ease;
}
.tp-btn svg, .tp-btn i { width: 16px; height: 16px; flex: none; }
.tp-btn:hover {
    background: #803E30;
    border-color: #F8DCC0;
    box-shadow: -5px -5px 10px rgba(0, 0, 0, 0.5), 5px 5px 10px rgba(0, 0, 0, 0.5), 10px 10px 20px rgba(0, 0, 0, 0.5), -10px -10px 20px rgba(0, 0, 0, 0.5);
}
.tp-btn:active {
    background: #4B2427;
    border-color: #803E30;
    box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5), -1px -1px 2px rgba(0, 0, 0, 0.5), inset 0px 8px 7.8px rgba(0, 0, 0, 0.59);
}
/* :disabled cobre <button>/<input> de verdade; .is-disabled é o
   equivalente pra <a>/<span> desabilitado visualmente (ex: "Anterior"
   na primeira página) — mesmo visual, sem depender de pseudo-classe
   que só existe em elemento de formulário. */
.tp-btn:disabled, .tp-btn.is-disabled {
    background: #2A2A2A;
    border-color: #3E3D38;
    color: #3E3D38;
    box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5), -1px -1px 2px rgba(0, 0, 0, 0.5);
    cursor: not-allowed;
    pointer-events: none;
}

/* Variantes de ação — mesma forma/sombra/raio do .tp-btn base, só a
   cor de destaque muda por ação (rodada de Botões, confirmada). Editar
   (dourado) e Excluir (vermelho) são fixos, sempre a mesma cor. */
.tp-btn.is-edit { border-color: #DCA15E; }
.tp-btn.is-edit:hover { background: #DCA15E; color: #131314; }
.tp-btn.is-edit:active { background: #6E4E23; border-color: #DCA15E; color: #F8DCC0; }

.tp-btn.is-delete { border-color: #FF4E3B; }
.tp-btn.is-delete:hover { background: #FF4E3B; }
.tp-btn.is-delete:active { background: #5A1811; border-color: #FF4E3B; }

/* Salvar NÃO tem cor fixa — nasce marrom igual ao botão comum (herda
   do .tp-btn base) e só vira verde quando .is-dirty é adicionada via
   JS (há uma alteração pendente ainda não salva). Quem liga/desliga
   essa classe é responsabilidade de cada form (ex: no 'input'/'change'
   do form, adicionar; no submit bem-sucedido, remover) — nenhum JS
   genérico faz isso sozinho hoje. */
.tp-btn.is-save.is-dirty { border-color: #A5FFA1; }
.tp-btn.is-save.is-dirty:hover { background: #A5FFA1; color: #131314; }
.tp-btn.is-save.is-dirty:active { background: #4C754A; border-color: #A5FFA1; color: #F8DCC0; }

/* Comprar — compacto de propósito (pedidos do dono, ago/2026, já
   confirmados antes: manter pequeno, não o tamanho do .tp-btn comum),
   reaproveita o CSS que .loja-jogo-buy-form/.loja-perso-buy-form
   (partials/loja-item-styles.ejs) já usam ao vivo hoje — is-buy sem
   modificador = Loja de Ossos (creme); .is-buy.is-hunt = Loja de
   Personalização (vermelho, moeda Caçadas). NÃO aplicado a nenhum
   botão real ainda (as duas lojas ficam como estão, pedido do dono) —
   só disponível aqui pra uso futuro fora do contexto de loja. */
.tp-btn.is-buy {
    height: auto;
    min-width: 92px;
    padding: 4px 10px;
    font-size: 10px;
    gap: 5px;
    background: radial-gradient(225.25% 94.36% at 0% 86.37%, #111111 0%, #1F1D20 57.07%, #29272A 91.53%);
    border-color: #F8DCC0;
    color: #F8DCC0;
}
.tp-btn.is-buy svg, .tp-btn.is-buy i { width: 12px; height: 12px; }
.tp-btn.is-buy:hover { background: radial-gradient(225.25% 94.36% at 0% 86.37%, #111111 0%, #1F1D20 57.07%, #29272A 91.53%); }
.tp-btn.is-buy:active { background: #4B2427; border-color: #DCA15E; color: #DCA15E; }
.tp-btn.is-buy.is-hunt { border-color: #803E30; color: #FF4E3B; }
.tp-btn.is-buy.is-hunt:hover { border-color: #FF4E3B; }

/* Spinner de botão "carregando" — usado por ajax-form.js (ver web/public/js/ajax-form.js)
   em qualquer form[data-ajax-form] da plataforma inteira, por isso mora no style.css
   global (não em loja-item-styles.ejs, que só é incluído em loja.ejs/inventario.ejs).
   Mesmo desenho visual do spinner que já existia ali (.loja-btn-spinner), só com nome
   genérico pra não sugerir que é exclusivo da Loja. */
.tp-ajax-spinner {
    display: inline-block;
    width: 12px;
    height: 12px;
    border: 2px solid rgba(255, 255, 255, 0.35);
    border-top-color: currentColor;
    border-radius: 50%;
    animation: tp-ajax-spin 0.6s linear infinite;
    vertical-align: -2px;
    margin-right: 6px;
}
@keyframes tp-ajax-spin {
    to { transform: rotate(360deg); }
}

/* ===================== CHECKBOX PADRÃO (.tp-checkbox) =====================
   Pedido do dono, 2026-09-20: "criar um padrão e seleção de opções pro
   site inteiro como essa que temos que selecionar o check" — auditoria
   real do código (grep por type="checkbox") achou 9 usos espalhados em
   5 arquivos (gameserver.ejs "Ativar whitelist", moderacao.ejs "Usar
   regex", lojajogo.ejs "Ativo"/espécies do kit, item-filter-bar.ejs
   filtro de categoria, pf-personalizacao-form.ejs "Remover plano de
   fundo"/"Esconder Kills/Deaths") — TODOS usando o checkbox cru do
   navegador, sem nenhum CSS próprio, o único controle de formulário do
   site sem identidade visual (inputs de texto já têm .input-container-
   premium, seleção em grade já tem .banner-picker-option, botões já têm
   .tp-btn). Este bloco define o padrão; NÃO foi aplicado a nenhum desses
   9 usos ainda (pedido do dono: só o guia por enquanto) — trocar um
   checkbox existente pra esse padrão é só adicionar as 2 classes abaixo
   no HTML que já existe, nada de reestruturar.

   APLICADO em todo o site, 2026-09-24 (pedido do dono: "aplique o padrão
   de checkbox em todo o site") — nos 9 usos citados acima, mais o
   checkbox novo de "?status" em gameserver.ejs. NÃO aplicado aos
   seletores tipo "chip"/pílula que já usam <input type="checkbox"> só
   como mecanismo de seleção por trás de um visual de pílula
   (.item-filter-checkbox, .lj-species-chip em lojajogo.ejs) — esses são
   um componente diferente de propósito (multi-seleção de tags), não um
   checkbox de verdade visualmente; aplicar esta classe ali regrediria um
   padrão que já está correto.

   Achado real na aplicação: uma 2ª definição de `.tp-checkbox` (mesmo
   nome de classe, conflitando) tinha sido criada do zero mais acima
   neste arquivo sem notar que este bloco já existia — cascade fazia os
   dois se misturarem (a de baixo, esta aqui, ganhava nas propriedades
   repetidas, mas o resultado ficava inconsistente/quebrado
   visualmente). Removida — este bloco é o único `.tp-checkbox` do
   arquivo agora.

   Decisões de identidade (mesma linguagem visual já usada no resto do
   site, não inventada do zero):
   - Estado marcado = exatamente a mesma inversão de cor do .icon-box
     (fundo dourado #DCA15E sólido + símbolo escuro #131314 por cima) —
     o mesmo motivo "dourado preenchido" que já significa "ativo/
     selecionado" em .banner-picker-option (borda dourada + glow) e em
     .tp-btn.is-edit:hover.
   - Estado normal = mesma receita de moldura de .input-container-premium/
     .banner-picker-thumb: fundo #1F1D20, borda dourada translúcida
     (25-40% opacidade) que fica sólida no hover/foco.
   - appearance:none no <input> DE VERDADE (não um <span> decorativo do
     lado) — mantém navegação por teclado/leitor de tela nativos, só
     redesenha o quadrado por cima; :focus-visible replica o mesmo anel
     de foco de .banner-picker-option.
   - Símbolo de check via mask-image (SVG embutido, mesmo traço do ícone
     "check" do Lucide já usado no resto do site via data-lucide) — não
     um <i data-lucide> de verdade porque este componente precisa
     funcionar sem depender de lucide.createIcons() já ter rodado.
   - Desabilitado = mesma opacidade 0.42 + cursor not-allowed de
     .pf-field-locked (padrão já usado pra qualquer campo travado por
     tier).

   Uso (mesmo HTML que os 9 pontos acima já têm, só + 2 classes):
   <label class="tp-checkbox-label">
       <input type="checkbox" class="tp-checkbox" name="..." value="1">
       <span>Texto da opção</span>
   </label>
   Combina normalmente com atributos existentes (checked, disabled,
   onchange, data-pf-preview etc.) — nenhum deles muda de comportamento. */
.tp-checkbox-label {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    font-family: 'Poppins', sans-serif;
    font-size: var(--fs-body-sm);
    color: #F8DCC0;
    user-select: none;
}
.tp-checkbox-label:has(.tp-checkbox:disabled) { cursor: not-allowed; }
.tp-checkbox {
    appearance: none;
    -webkit-appearance: none;
    position: relative;
    width: 18px;
    height: 18px;
    flex: none;
    margin: 0;
    border-radius: 5px;
    border: 1px solid rgba(220, 161, 94, 0.35);
    background: #1F1D20;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
}
.tp-checkbox:hover:not(:disabled) { border-color: rgba(220, 161, 94, 0.75); }
.tp-checkbox:focus-visible { outline: 2px solid #DCA15E; outline-offset: 2px; }
.tp-checkbox:checked { background: #DCA15E; border-color: #DCA15E; }
/* Check embutido via mask (não background-image) pra poder trocar de cor
   com currentColor/background-color como qualquer outro elemento — o
   mesmo traço (stroke-width 3, arredondado) que os ícones Lucide do
   resto do site usam. */
.tp-checkbox:checked::after {
    content: '';
    position: absolute;
    inset: 0;
    background-color: #131314;
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
    -webkit-mask-size: 68%;
    mask-size: 68%;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
}
.tp-checkbox:disabled { opacity: 0.42; cursor: not-allowed; }
.report-page-info { font-size: 0.7rem; opacity: 0.5; }

/* Créditos de arte (rodapé de toda página, pedido do dono 2026-09-30) —
   botão "Artists" ao lado de "Termos de Serviço"/"BY: KNUST SEIER VI"
   abre este dialog nativo com a atribuição de ícones de terceiros
   (Flaticon etc.). Mesma identidade visual dos outros dialogs do
   projeto (.pool-req-dialog em dev-passe-batalha.ejs/dev-loja-jogo.ejs),
   trazida pra cá porque este é o único item de rodapé compartilhado por
   TODA página do dashboard — hero.ejs/termos.ejs/portal.ejs não
   carregam este arquivo, então duplicam esta mesma regra localmente
   (mesmo padrão já usado por eles pra outras classes compartilhadas). */
dialog.credits-dialog {
    background: #1A1A1A;
    color: #F8DCC0;
    border: 1px solid rgba(220, 161, 94, 0.35);
    border-radius: 14px;
    padding: 18px;
    width: calc(100% - 32px);
    max-width: 380px;
    max-height: calc(100vh - 64px);
    overflow-y: auto;
}
dialog.credits-dialog::backdrop { background: rgba(0, 0, 0, 0.65); }
.credits-dialog-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.credits-dialog-head h3 { font-family: 'Poppins', sans-serif; font-weight: 700; font-size: 0.95rem; margin: 0; color: #F8DCC0; }
.credits-dialog-close { flex: none; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; background: transparent; border: 1px solid rgba(220, 161, 94, 0.3); border-radius: 6px; color: #F8DCC0; opacity: 0.7; cursor: pointer; font-size: 0.95rem; line-height: 1; transition: opacity 0.15s ease, background 0.15s ease; }
.credits-dialog-close:hover { opacity: 1; background: rgba(220, 161, 94, 0.12); }
.credits-dialog-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; font-family: 'Poppins', sans-serif; font-size: 0.8rem; }
.credits-dialog-list a { color: #DCA15E; text-decoration: underline; }
.credits-dialog-list a:hover { color: #F8DCC0; }
.credits-footer-btn { background: none; border: none; padding: 0; cursor: pointer; font: inherit; }

/* Revisão geral de responsividade mobile (pedido do dono, 2026-09-30:
   "revise pontos de responsividade para mobile em todo o site") —
   ajustes GLOBAIS (valem pra toda página que usa estas classes
   compartilhadas), separados dos ajustes específicos por página (esses
   ficam no <style> local de cada arquivo). */
@media (max-width: 767px) {
    /* Botões um pouco menores no mobile (pedido: "Botões em geral também
       podem diminuir um pouco") — .btn-primary perde o min-width:232px
       fixo (que sozinho já força overflow horizontal numa tela de
       ~360px com 2 botões lado a lado).

       2ª rodada (pedido do dono, 2026-10-01: "diminuir mais um pouco
       todos os botões e componentes de dropmenu, select e busca na
       versão mobile") — a 1ª rodada já tinha reduzido uma vez; estes
       valores encolhem mais um passo por cima daquele. */
    .tp-btn { padding: 6px 13px; height: 31px; font-size: 11.5px; gap: 6px; }
    .tp-btn svg, .tp-btn i { width: 12px; height: 12px; }
    .btn-primary { min-width: 0; padding: 4px 12px; height: 31px; }

    /* Campos de texto/dropdown/busca um pouco menores (pedido: "Dropmenus,
       caixas de escrita, e caixas de busca podem também diminuir um
       pouco") — mesma 2ª rodada acima. */
    .input-container-premium { min-height: 38px; max-width: 100%; }
    .icon-box { width: 34px; font-size: 0.95rem; }
    .input-premium-field { font-size: 0.78rem; padding: 0 10px; }

    /* Dropdown 100% nosso (custom-select.js) e "Adicionar cargo/
       dinossauro" (role-picker.js) nunca tinham nenhuma redução pro
       mobile — mesma 2ª rodada, "componentes de dropmenu, select"
       cobre o gatilho/popup/busca/lista dos dois, não só o campo de
       input cru acima. */
    .tp-select-trigger { min-height: 38px; padding: 0 10px; font-size: 0.78rem; }
    .tp-custom-select-search { padding: 8px 10px; font-size: 0.78rem; }
    .tp-custom-select-list li { padding: 8px 10px; font-size: 0.8rem; }

    /* Paginação (Reportes/Denúncias) — indicador da página ACIMA dos
       botões de Anterior/Próxima, em vez de espremido ENTRE eles
       (pedido do dono: "coloque o indicador da página acima dos botões
       de navegação"). order:-1 + flex-basis:100% no texto força ele pra
       linha própria antes dos 2 botões (que ficam juntos, lado a lado,
       na linha de baixo) — sem precisar mudar a ORDEM real no HTML
       (Anterior/texto/Próxima continua igual pro desktop, onde já
       funcionava numa linha só). */
    .report-pagination { flex-wrap: wrap; }
    .report-page-info { order: -1; flex-basis: 100%; text-align: center; }

    /* Linha de report/denúncia quebrando a identificação do jogador
       (pedido do dono: "a linha de denúncias... fica quebrada cortando
       identificação do jogador devido ao indicador do servidor") —
       .tp-list-row-head nunca teve flex-wrap, então o selo de servidor
       (.report-guild-badge, tamanho fixo — nome do servidor pode ser
       longo) ficava OBRIGATORIAMENTE na mesma linha que usuário/AGID/
       data, espremendo esse bloco até truncar/quebrar de forma feia.
       Com wrap, o selo desce pra própria linha (ainda alinhado à
       direita, graças ao margin-left:auto que .tp-list-row-actions já
       tinha) só quando não cabe, em vez de forçar tudo numa linha só. */
    .tp-list-row-head { flex-wrap: wrap; }
}
/* -------- Janela "Configurar requisito/recompensa" (dialog.pool-req-dialog)
   — usada por partials/requirement-form.ejs, mission-reward-form.ejs e
   battle-pass-reward-form.ejs (dev /dev/passe-batalha, /dev/imagens e
   Loja de Jogo). As regras dela moravam só na antiga /dev/loja-jogo
   (retirada em a03312d0), então sobrou select branco do navegador, texto
   de explicação sem estilo e "+ Adicionar" parecendo texto solto (achado
   do dono, 2026-09-29). Escopado no dialog pra não mexer em outros
   .pool-price-row/.pool-req-value-row da página; tamanhos no padrão dos
   campos do resto do site em vez dos 0.6-0.7rem antigos. -------- */
dialog.pool-req-dialog { font-family: 'Poppins', sans-serif; }
dialog.pool-req-dialog select,
dialog.pool-req-dialog input[type="number"],
dialog.pool-req-dialog input[type="text"],
dialog.pool-req-dialog input[type="date"] {
    flex: 1;
    min-width: 0;
    width: 100%;
    box-sizing: border-box;
    background: #1F1D20;
    border: 1px solid rgba(220, 161, 94, 0.45);
    border-radius: 8px;
    padding: 8px 10px;
    color: #F8DCC0;
    font-family: 'Poppins', sans-serif;
    font-size: 0.85rem;
    color-scheme: dark;
}
dialog.pool-req-dialog select:focus,
dialog.pool-req-dialog input:focus { outline: none; border-color: #DCA15E; }
dialog.pool-req-dialog label { font-size: 0.75rem; opacity: 0.7; }
dialog.pool-req-dialog .pool-req-rows { display: flex; flex-direction: column; gap: 12px; }
dialog.pool-req-dialog .pool-req-row { display: flex; flex-direction: column; gap: 8px; }
dialog.pool-req-dialog .pool-req-row + .pool-req-row { padding-top: 12px; border-top: 1px dashed rgba(220, 161, 94, 0.2); }
dialog.pool-req-dialog .pool-price-row { display: flex; gap: 8px; align-items: center; }
dialog.pool-req-dialog .pool-req-value-row { display: flex; align-items: center; gap: 8px; }
dialog.pool-req-dialog .pool-req-value-row label { flex: none; white-space: nowrap; }
dialog.pool-req-dialog .pool-req-value-row input,
dialog.pool-req-dialog .pool-req-value-row select { font-size: 0.85rem; padding: 8px 10px; border-radius: 8px; }
dialog.pool-req-dialog .pool-req-hint { font-size: 0.75rem; opacity: 0.55; line-height: 1.45; font-style: italic; margin: 0; }
dialog.pool-req-dialog .pool-req-remove {
    flex: none; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center;
    background: transparent; border: 1px solid rgba(220, 161, 94, 0.3); border-radius: 8px;
    color: #F8DCC0; opacity: 0.7; cursor: pointer; font-size: 1rem; line-height: 1;
    transition: opacity 0.15s ease, background 0.15s ease;
}
dialog.pool-req-dialog .pool-req-remove:hover { opacity: 1; background: rgba(220, 161, 94, 0.12); }
dialog.pool-req-dialog .pool-req-add {
    align-self: flex-start; font-family: 'Poppins', sans-serif; font-weight: 600; font-size: 0.8rem;
    padding: 8px 14px; border-radius: 10px; border: 1px dashed rgba(220, 161, 94, 0.45);
    background: transparent; color: #DCA15E; cursor: pointer; transition: background 0.15s ease;
}
dialog.pool-req-dialog .pool-req-add:hover { background: rgba(220, 161, 94, 0.1); }
dialog.pool-req-dialog .pool-req-add:disabled { opacity: 0.35; cursor: not-allowed; }
dialog.pool-req-dialog .pool-req-dialog-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 4px; }
dialog.pool-req-dialog .pool-toggle-btn,
dialog.pool-req-dialog .pool-price-submit {
    font-family: 'Poppins', sans-serif; font-weight: 600; font-size: 0.85rem; height: 39px; padding: 0 18px;
    border-radius: 12px; cursor: pointer; transition: background 0.15s ease, border-color 0.15s ease;
}
dialog.pool-req-dialog .pool-toggle-btn { background: #2A2A2A; border: 1px solid rgba(248, 220, 192, 0.25); color: #F8DCC0; }
dialog.pool-req-dialog .pool-toggle-btn:hover { background: #333; }
dialog.pool-req-dialog .pool-price-submit { background: #DCA15E; border: none; color: #131314; }
dialog.pool-req-dialog .pool-price-submit:hover { background: #F8DCC0; }

/* Caixa base da janela + resumo "texto + Configurar" — antes só existiam
   inline em dev-passe-batalha.ejs; as missões do servidor (events.ejs,
   2026-09-29) usam o mesmo formulário, então valem pro site todo agora. */
dialog.pool-req-dialog { background: #1A1A1A; color: #F8DCC0; border: 1px solid rgba(220, 161, 94, 0.35); border-radius: 14px; padding: 18px; width: calc(100% - 32px); max-width: 420px; max-height: calc(100vh - 64px); overflow-y: auto; }
dialog.pool-req-dialog::backdrop { background: rgba(0, 0, 0, 0.65); }
dialog.pool-req-dialog .pool-req-dialog-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 4px; }
dialog.pool-req-dialog .pool-req-dialog-head h3 { font-family: 'Poppins', sans-serif; font-weight: 700; font-size: 0.9rem; margin: 0; color: #F8DCC0; }
dialog.pool-req-dialog .pool-req-dialog-close { flex: none; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; background: transparent; border: 1px solid rgba(220, 161, 94, 0.3); border-radius: 8px; color: #F8DCC0; opacity: 0.7; cursor: pointer; font-size: 1rem; line-height: 1; }
dialog.pool-req-dialog .pool-req-dialog-close:hover { opacity: 1; background: rgba(220, 161, 94, 0.12); }
.pool-requirement-summary { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; min-width: 0; }
.pool-requirement-summary .pool-price-current { font-family: 'Poppins', sans-serif; font-size: 0.8rem; color: #F8DCC0; opacity: 0.75; overflow-wrap: anywhere; }


/* Frase "Quem pode usar" logo abaixo do separador de uma sessão de
   configuração (partials/section-roles-note.ejs, 2026-09-29): cargos
   configurados na cor que eles têm no Discord, estilo de menção. */
.section-roles-note { display: block; margin: 0; font-family: 'Poppins', sans-serif; font-size: 0.78rem; line-height: 1.5; color: #F8DCC0; opacity: 0.85; }
.section-roles-note > i, .section-roles-note > svg { display: inline-block; width: 14px; height: 14px; color: #DCA15E; vertical-align: -2px; margin-right: 4px; }
.section-role-chip { font-weight: 600; border-radius: 4px; padding: 0 5px; white-space: nowrap; }
