/* O console.
 *
 * Reusa os TOKENS do site (tokens.css) e quase nada da casca dele: um painel
 * administrativo tem outra densidade. O site respira porque quem chega está decidindo
 * se fica; aqui a pessoa já está trabalhando e cada linha a mais visível na tela é uma
 * rolagem a menos.
 *
 * Então: fonte menor, tabelas apertadas, números tabulares em tudo que se compara. */

.console {
    display: grid;
    grid-template-columns: 15rem minmax(0, 1fr);
    min-block-size: 100vh;
}

@media (max-width: 60rem) {
    /* Abaixo disso a lateral vira topo. Uma coluna de 15rem num celular come metade da
       largura, e a tabela — que é o conteúdo — fica ilegível. */
    .console { grid-template-columns: minmax(0, 1fr); }
    .console-nav { position: static; block-size: auto; }
    .console-nav nav { flex-direction: row; flex-wrap: wrap; }
}

/* ── Navegação ───────────────────────────────────────────────────────────────── */

.console-nav {
    position: sticky;
    inset-block-start: 0;
    block-size: 100vh;
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding: var(--space-5) var(--space-4);
    background: var(--bg-raised);
    border-inline-end: 1px solid var(--line);
}

.console-brand {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-weight: 700;
    font-size: var(--text-lg);
    text-decoration: none;
    color: var(--text-strong);
}

.console-nav nav { display: flex; flex-direction: column; gap: 2px; }

.console-link {
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    text-decoration: none;
    color: var(--text);
    font-size: var(--text-sm);
}

.console-link:hover { background: var(--bg-sunken); }

/* NavLink marca sozinho, comparando com a URL. */
.console-link.active {
    background: var(--brand-50);
    color: var(--brand-700);
    font-weight: 600;
}

.console-who {
    margin-block-start: auto;
    padding-block-start: var(--space-4);
    border-block-start: 1px solid var(--line);
    font-size: var(--text-sm);
}

.console-who-name { font-weight: 600; }
.console-who-role { color: var(--text-muted); }
.console-out { display: block; margin-block-start: var(--space-3); font-size: var(--text-sm); }

/* ── Miolo ───────────────────────────────────────────────────────────────────── */

.console-main { padding: var(--space-6); max-inline-size: 100%; }

.console-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    margin-block-end: var(--space-5);
}

.console-head h1 { margin: 0; }
.console-head-actions { display: flex; gap: var(--space-2); }

.console-section { margin-block: var(--space-6) var(--space-3); font-size: var(--text-lg); }

/* A tela de barreira, para quem não é do quadro. Centrada e sozinha: não há console
   por trás dela para espiar. */
.console-gate {
    display: grid;
    place-items: center;
    min-block-size: 100vh;
    padding: var(--space-6);
}

.console-gate .card { max-inline-size: 28rem; text-align: center; }

/* ── Tabelas ─────────────────────────────────────────────────────────────────── */

/* O contêiner rola, não a página. Sem isto uma tabela de doze colunas empurra a
   largura do documento e a navegação lateral sai da tela. */
.table-wrap {
    overflow-x: auto;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    background: var(--bg-raised);
}

.table { inline-size: 100%; border-collapse: collapse; font-size: var(--text-sm); }

.table th {
    text-align: start;
    padding: var(--space-2) var(--space-3);
    border-block-end: 1px solid var(--line);
    color: var(--text-muted);
    font-weight: 600;
    white-space: nowrap;
    /* Cabeçalho fixo na rolagem vertical: numa lista de cinquenta linhas, sem isto
       perde-se de vista qual coluna é qual na terceira tela. */
    position: sticky;
    inset-block-start: 0;
    background: var(--bg-raised);
}

.table td { padding: var(--space-2) var(--space-3); border-block-end: 1px solid var(--line); }
.table tbody tr:last-child td { border-block-end: none; }
.table tbody tr:hover { background: var(--bg-sunken); }

/* Linha que merece atenção. Fundo tênue e não vermelho forte: com vinte linhas
   marcadas, vermelho forte é uma tela que ninguém lê. */
.table tr.row-warn td { background: oklch(0.96 0.04 75 / 0.5); }
.table tr.row-fail td { background: oklch(0.95 0.05 25 / 0.5); }

.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.9em; }

.truncate { max-inline-size: 22rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.row-actions { display: flex; gap: var(--space-2); white-space: nowrap; }

/* ── Filtros e paginação ─────────────────────────────────────────────────────── */

.filters {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: center;
    margin-block-end: var(--space-4);
}

.filters .input { inline-size: auto; min-inline-size: 12rem; }

.check { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); }

.paginator {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-block-start: var(--space-3);
}

.paginator-buttons { display: flex; gap: var(--space-2); }

.tabs { display: flex; gap: 2px; margin-block-end: var(--space-4); border-block-end: 1px solid var(--line); }

.tab {
    padding: var(--space-2) var(--space-4);
    border: none;
    background: none;
    cursor: pointer;
    color: var(--text-muted);
    font-size: var(--text-sm);
    border-block-end: 2px solid transparent;
}

.tab.is-active { color: var(--brand-700); border-block-end-color: var(--brand-600); font-weight: 600; }

/* ── Números e etiquetas ─────────────────────────────────────────────────────── */

.metric-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
    gap: var(--space-3);
}

.metric {
    padding: var(--space-3);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    background: var(--bg-raised);
}

.metric-label { font-size: var(--text-sm); color: var(--text-muted); }
.metric-value { font-size: var(--text-xl); font-weight: 700; }
.metric-value.is-alarm, .is-alarm { color: var(--danger-600); }

.tag {
    display: inline-block;
    padding: 1px 7px;
    border-radius: 999px;
    background: var(--bg-sunken);
    border: 1px solid var(--line);
    font-size: 0.75rem;
    white-space: nowrap;
}

.tag-admin { background: var(--brand-50); border-color: var(--brand-600); color: var(--brand-700); }
.tag-moderator { background: oklch(0.95 0.05 250); border-color: oklch(0.6 0.14 250); }
.tag-online { background: oklch(0.94 0.08 150); border-color: oklch(0.6 0.14 150); }
.tag-warn { background: oklch(0.95 0.08 75); border-color: oklch(0.65 0.14 75); }
.tag-staff { background: oklch(0.94 0.06 300); border-color: oklch(0.6 0.14 300); }

.kv { display: grid; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); gap: var(--space-3); }
.kv > div { display: flex; flex-direction: column; gap: 2px; }
.kv-label { font-size: var(--text-sm); color: var(--text-muted); }

.edit-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: var(--space-3); }

/* ── Diálogo de motivo ───────────────────────────────────────────────────────── */

.prompt-backdrop {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: grid;
    place-items: center;
    padding: var(--space-4);
    background: oklch(0 0 0 / 0.45);
}

.prompt {
    inline-size: min(32rem, 100%);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-5);
    border-radius: var(--radius-lg);
    /* Opaco de propósito. Um diálogo translúcido sobre uma tabela de dados deixa os
       dois legíveis pela metade — e este diálogo é onde se digita o motivo de um
       banimento. */
    background: var(--bg-raised);
    box-shadow: 0 24px 64px oklch(0 0 0 / 0.3);
}

.prompt h2 { margin: 0; }
.prompt-actions { display: flex; justify-content: flex-end; gap: var(--space-2); }

/* ── Analytics ───────────────────────────────────────────────────────────────── */

.examples { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; font-size: var(--text-sm); }

.link {
    border: none;
    background: none;
    padding: 0;
    cursor: pointer;
    color: var(--brand-700);
    text-decoration: underline;
    font: inherit;
}

.saved-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr)); gap: var(--space-3); }

.saved-sql {
    margin: 0;
    padding: var(--space-2);
    background: var(--bg-sunken);
    border-radius: var(--radius-sm);
    font-size: 0.8rem;
    max-block-size: 8rem;
    overflow: auto;
    white-space: pre-wrap;
}

/* ── Gráfico ─────────────────────────────────────────────────────────────────── */

.spark { inline-size: 100%; block-size: 8rem; }

.spark-line { fill: none; stroke-width: 0.6; vector-effect: non-scaling-stroke; }
.spark-signups { stroke: var(--brand-600); }
.spark-logins { stroke: oklch(0.6 0.14 250); }

.spark-legend { display: flex; gap: var(--space-4); font-size: var(--text-sm); margin-block-start: var(--space-2); }
.spark-key::before { content: "—"; margin-inline-end: 4px; font-weight: 700; }
.spark-key.spark-signups { color: var(--brand-700); }
.spark-key.spark-logins { color: oklch(0.5 0.14 250); }

/* ═══════════════════════════════════════════════════════════════════════════════
   ESTADOS, MOVIMENTO E DENSIDADE
   ═══════════════════════════════════════════════════════════════════════════════

   Tudo abaixo existe por causa de um retorno duro: o console estava "porco, zero
   pensado em experiência". Estava mesmo — era uma parede de caixas iguais, sem
   estado de erro, sem hierarquia e sem sinal de vida.

   A régua aqui não é "ficar bonito". É: quem abre sabe para onde olhar, sabe se o
   que vê é de agora, e nunca fica preso num estado que não conta a verdade. */

/* Uma preferência acessível respeitada de uma vez, para o arquivo inteiro. Quem
   pediu menos movimento no sistema operacional não deveria ter que pedir de novo. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* ── Esqueleto ──────────────────────────────────────────────────────────────────
   Substitui o texto "Loading…". Tem a FORMA do que vem, então o layout não pula
   quando o dado chega, e o brilho diz que algo está acontecendo sem um spinner
   girando no vazio. O atraso escalonado por linha (--i) dá a sensação de carga
   progressiva em vez de um bloco piscando junto. */

.skeleton-stack { display: flex; flex-direction: column; gap: var(--space-2); }

.skeleton-row {
    block-size: 2.75rem;
    border-radius: var(--radius-sm);
    background: linear-gradient(90deg,
        var(--bg-sunken) 25%, var(--bg-raised) 37%, var(--bg-sunken) 63%);
    background-size: 400% 100%;
    animation: shimmer 1.4s ease-in-out infinite;
    animation-delay: calc(var(--i, 0) * 90ms);
}

@keyframes shimmer {
    0%   { background-position: 100% 50%; }
    100% { background-position: 0 50%; }
}

/* ── Falha ──────────────────────────────────────────────────────────────────────
   O estado que faltava por completo, e a razão de "carregando para sempre". Diz o
   que houve e oferece a ação — um erro sem saída é um beco. */

.panel-fail {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-5);
    border: 1px solid oklch(0.75 0.14 25);
    border-radius: var(--radius-md);
    background: oklch(0.97 0.03 25);
    animation: rise 180ms ease-out;
}

.panel-fail-icon { font-size: 1.5rem; }
.panel-fail .btn { margin-inline-start: auto; }

/* ── Vazio ──────────────────────────────────────────────────────────────────────
   Centrado e com instrução. "Nada encontrado" deixa sem próximo passo; dizer o que
   costuma causar o vazio transforma o beco numa orientação. */

.panel-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-7) var(--space-5);
    border: 1px dashed var(--line);
    border-radius: var(--radius-md);
    text-align: center;
    animation: rise 180ms ease-out;
}

.panel-empty-icon { font-size: 2rem; opacity: 0.6; }
.panel-empty p { max-inline-size: 34rem; }

@keyframes rise {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: none; }
}

/* Conteúdo durante uma revalidação: apaga um pouco em vez de sumir. É o que faz a
   atualização automática não piscar a tabela na cara de quem está lendo. */
.panel-body { animation: rise 160ms ease-out; }
.panel-body.is-stale { opacity: 0.55; transition: opacity 120ms ease-out; }

/* ── Sinal de vida ──────────────────────────────────────────────────────────────
   O circuito do Blazor já é um WebSocket; isto é o que torna esse fato visível. */

.live-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: 3px 10px;
    border-radius: 999px;
    border: 1px solid var(--line);
    background: var(--bg-raised);
    font-size: var(--text-sm);
    color: var(--text-muted);
}

.live-dot {
    inline-size: 7px;
    block-size: 7px;
    border-radius: 50%;
    background: oklch(0.65 0.16 150);
}

.live-badge.is-pulsing .live-dot { animation: pulse 1s ease-in-out infinite; }

@keyframes pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50%      { opacity: 0.35; transform: scale(0.8); }
}

/* O pontinho dentro de uma etiqueta "online"/"active". Mesmo vocabulário visual do
   indicador de vida, em miniatura. */
.pip {
    display: inline-block;
    inline-size: 5px;
    block-size: 5px;
    border-radius: 50%;
    background: currentColor;
    margin-inline-end: 5px;
    vertical-align: middle;
}

/* ── Hierarquia da visão geral ──────────────────────────────────────────────────
   Quatro números grandes primeiro. Antes eram vinte e quatro do mesmo tamanho —
   e tudo com o mesmo peso é o mesmo que nada com peso. */

.hero-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: var(--space-4);
    margin-block-end: var(--space-6);
}

.hero-card {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--space-5);
    border-radius: var(--radius-lg);
    background: linear-gradient(160deg, var(--bg-raised), var(--bg-sunken));
    border: 1px solid var(--line);
    transition: transform 140ms ease-out, box-shadow 140ms ease-out;
}

.hero-card:hover { transform: translateY(-2px); box-shadow: 0 8px 24px oklch(0 0 0 / 0.08); }

.hero-label { font-size: var(--text-sm); color: var(--text-muted); }
.hero-value { font-size: 2.5rem; font-weight: 700; line-height: 1.1; }
.hero-foot { font-size: var(--text-sm); color: var(--text-muted); }

/* ── O que precisa de atenção ───────────────────────────────────────────────────
   Aparece só quando há algo. Um bloco que fica vazio na maioria dos dias é um bloco
   que SIGNIFICA alguma coisa no dia em que aparece. */

.attention {
    margin-block-end: var(--space-6);
    border: 1px solid oklch(0.8 0.1 75);
    border-radius: var(--radius-md);
    background: oklch(0.98 0.02 75);
    overflow: hidden;
}

.attention-head {
    margin: 0;
    padding: var(--space-3) var(--space-4);
    font-size: var(--text-sm);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: oklch(0.45 0.1 75);
    border-block-end: 1px solid oklch(0.9 0.05 75);
}

.attention-item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    text-decoration: none;
    color: inherit;
    border-block-end: 1px solid oklch(0.94 0.03 75);
    transition: background 120ms ease-out;
}

.attention-item:last-child { border-block-end: none; }
.attention-item:hover { background: oklch(0.96 0.04 75); }

.attention-dot {
    inline-size: 8px; block-size: 8px; border-radius: 50%;
    background: oklch(0.7 0.16 75); flex: none;
}

/* A seta desliza no hover: afordância de "isto leva a algum lugar", sem precisar
   sublinhar o texto inteiro. */
.attention-go { margin-inline-start: auto; transition: transform 140ms ease-out; }
.attention-item:hover .attention-go { transform: translateX(3px); }

.chart-card { margin-block-end: var(--space-6); }
.detail-block .metric-grid { margin-block-end: var(--space-4); }

/* ── Tabela: densidade e interação ──────────────────────────────────────────────*/

.table-hover tbody tr { transition: background 100ms ease-out; cursor: default; }
.table-hover tbody tr.is-open { background: var(--bg-sunken); }

.cell-strong { font-weight: 600; color: var(--text-strong); }

/* A coluna do triângulo de expansão. Largura fixa para que o triângulo não empurre
   o nome de linha para linha quando gira. */
.col-grip { inline-size: 1.5rem; padding-inline-end: 0 !important; }

.grip {
    display: inline-block;
    color: var(--text-muted);
    transition: transform 160ms ease-out;
}

.grip.is-open { transform: rotate(90deg); }

.row-detail td { background: var(--bg-sunken); padding: var(--space-4) !important; }

.detail-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    gap: var(--space-3);
    animation: rise 160ms ease-out;
}

.detail-grid > div { display: flex; flex-direction: column; gap: 1px; }

/* Cabeçalho ordenável. O botão ocupa a célula inteira para que a área de clique
   seja a coluna, e não só as letras. */
.sortable { padding: 0 !important; }

.sort-btn {
    inline-size: 100%;
    display: flex;
    align-items: center;
    gap: 4px;
    padding: var(--space-2) var(--space-3);
    border: none;
    background: none;
    font: inherit;
    color: inherit;
    cursor: pointer;
    white-space: nowrap;
}

.sort-btn:hover { background: var(--bg-sunken); }
.sortable.is-sorted .sort-btn { color: var(--brand-700); }
.sort-arrow { opacity: 0.4; font-size: 0.7em; }
.sortable.is-sorted .sort-arrow { opacity: 1; }

/* ── Medidor de HP/MP ───────────────────────────────────────────────────────────
   A largura vem de uma custom property justamente para a transição pegar: quando a
   atualização automática traz um valor novo, a barra ANDA — e "esse personagem
   tomou dano agora" fica visível sem ninguém avisar. */

.gauge {
    position: relative;
    inline-size: 6.5rem;
    block-size: 1.1rem;
    border-radius: 3px;
    background: var(--bg-sunken);
    overflow: hidden;
    margin-block-end: 2px;
}

.gauge-fill {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    inline-size: var(--fill, 0%);
    transition: inline-size 400ms cubic-bezier(0.22, 1, 0.36, 1);
}

.gauge-hp .gauge-fill { background: oklch(0.68 0.16 25); }
.gauge-mp .gauge-fill { background: oklch(0.62 0.14 250); }

.gauge-text {
    position: relative;
    display: block;
    text-align: center;
    font-size: 0.7rem;
    line-height: 1.1rem;
    color: var(--text-strong);
    mix-blend-mode: luminosity;
}

/* ── Filtros ────────────────────────────────────────────────────────────────────*/

.field-search { position: relative; display: flex; align-items: center; }
.field-search .field-icon { position: absolute; inset-inline-start: 10px; color: var(--text-muted); }
.field-search .input { padding-inline-start: 2rem; }

.input-narrow { max-inline-size: 8rem; }

/* Botões segmentados no lugar de um <select> de três opções: um clique em vez de
   dois, e as três alternativas ficam visíveis sem abrir nada. */
.segmented {
    display: inline-flex;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    overflow: hidden;
}

.segment {
    padding: var(--space-2) var(--space-3);
    border: none;
    background: var(--bg-raised);
    cursor: pointer;
    font-size: var(--text-sm);
    color: var(--text-muted);
    transition: background 120ms ease-out, color 120ms ease-out;
}

.segment + .segment { border-inline-start: 1px solid var(--line); }
.segment:hover { background: var(--bg-sunken); }
.segment.is-on { background: var(--brand-600); color: white; font-weight: 600; }

/* ── Etiquetas de estado de conta ───────────────────────────────────────────────*/

.tag-status-active { background: oklch(0.94 0.07 150); border-color: oklch(0.65 0.13 150); }
.tag-status-pending_verification { background: oklch(0.96 0.06 75); border-color: oklch(0.7 0.12 75); }
.tag-status-suspended, .tag-status-banned { background: oklch(0.95 0.06 25); border-color: oklch(0.68 0.14 25); }
.tag-status-erased { background: var(--bg-sunken); color: var(--text-muted); }

/* ── Navegação: o item ativo se move ────────────────────────────────────────────*/

.console-link { transition: background 120ms ease-out, color 120ms ease-out; position: relative; }

.console-link.active::before {
    content: "";
    position: absolute;
    inset-block: 6px;
    inset-inline-start: 0;
    inline-size: 3px;
    border-radius: 2px;
    background: var(--brand-600);
}

/* Foco visível em tudo que é operável. Num painel onde os cliques removem banimento,
   navegar por teclado sem saber onde se está é como se erra o alvo. */
.console-link:focus-visible,
.segment:focus-visible,
.sort-btn:focus-visible,
.tab:focus-visible,
.link:focus-visible {
    outline: 2px solid var(--brand-600);
    outline-offset: 2px;
}
