/* ==========================================================================
   VULT0 — ajustes sobre o Fluent UI.

   A aparência vem dos componentes e dos design tokens do Fluent UI
   (--neutral-*, --accent-*, --type-ramp-*). O que sobra aqui é apenas o que
   nenhum componente cobre.
   ========================================================================== */

/* O FluentLayout usa height:100%; sem altura na raiz ele colapsa na altura do
   conteúdo e o rodapé sobe para o meio da tela. */

html,
body {
    height: 100%;
    /* Firefox */
    scrollbar-color: var(--neutral-foreground-active) transparent;
    scrollbar-width: thin;
}

body {
    margin: 0;
}

    /* Edge, Chrome, Safari */
    html::-webkit-scrollbar,
    body::-webkit-scrollbar {
        width: 8px;
        height: 8px;
        background: transparent;
    }

    html::-webkit-scrollbar-track,
    body::-webkit-scrollbar-track {
        background: transparent;
    }

    html::-webkit-scrollbar-thumb,
    body::-webkit-scrollbar-thumb {
        background-color: var(--neutral-foreground-active);
        border-radius: 999px;
    }

    html::-webkit-scrollbar-button,
    body::-webkit-scrollbar-button {
        display: none;
        width: 0;
        height: 0;
    }

/* --- espera pelos componentes ---------------------------------------------
   Ver wwwroot/fluent-ready.js. Enquanto os custom elements do Fluent UI nao
   estao registrados, o conteudo fica invisivel — mas o fundo do tema ja esta
   pintado, entao o que se ve durante a espera e a cor final da pagina.

   `visibility` e nao `display`: o layout continua sendo calculado, entao a
   pagina nao "salta" ao aparecer.

   Se o JavaScript estiver desativado, o seletor :root:not(.fluent-pronto)
   esconderia a pagina para sempre. O <noscript> abaixo desfaz isso: sem JS os
   componentes nunca serao registrados mesmo, e o conteudo semantico (SSR) e
   melhor do que nada. */

:root:not(.fluent-pronto) body > * {
    visibility: hidden;
}

/* O fundo é o token que o Fluent reserva para ficar atrás dos cartões. Era o
   --neutral-layer-1, que é a mesma cor do fluent-card (#272727 nos dois,
   medido): o cartão só se separava da página pela borda de 1px, e o conteúdo
   parecia solto sobre o circuito. */
body {
    color: var(--neutral-foreground-rest);
    background: var(--neutral-layer-card-container);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 304 304' width='200' height='200' %3E%3Cpath fill='%23D0B7E4' fill-opacity='0.05' d='M44.1 224a5 5 0 1 1 0 2H0v-2h44.1zm160 48a5 5 0 1 1 0 2H82v-2h122.1zm57.8-46a5 5 0 1 1 0-2H304v2h-42.1zm0 16a5 5 0 1 1 0-2H304v2h-42.1zm6.2-114a5 5 0 1 1 0 2h-86.2a5 5 0 1 1 0-2h86.2zm-256-48a5 5 0 1 1 0 2H0v-2h12.1zm185.8 34a5 5 0 1 1 0-2h86.2a5 5 0 1 1 0 2h-86.2zM258 12.1a5 5 0 1 1-2 0V0h2v12.1zm-64 208a5 5 0 1 1-2 0v-54.2a5 5 0 1 1 2 0v54.2zm48-198.2V80h62v2h-64V21.9a5 5 0 1 1 2 0zm16 16V64h46v2h-48V37.9a5 5 0 1 1 2 0zm-128 96V208h16v12.1a5 5 0 1 1-2 0V210h-16v-76.1a5 5 0 1 1 2 0zm-5.9-21.9a5 5 0 1 1 0 2H114v48H85.9a5 5 0 1 1 0-2H112v-48h12.1zm-6.2 130a5 5 0 1 1 0-2H176v-74.1a5 5 0 1 1 2 0V242h-60.1zm-16-64a5 5 0 1 1 0-2H114v48h10.1a5 5 0 1 1 0 2H112v-48h-10.1zM66 284.1a5 5 0 1 1-2 0V274H50v30h-2v-32h18v12.1zM236.1 176a5 5 0 1 1 0 2H226v94h48v32h-2v-30h-48v-98h12.1zm25.8-30a5 5 0 1 1 0-2H274v44.1a5 5 0 1 1-2 0V146h-10.1zm-64 96a5 5 0 1 1 0-2H208v-80h16v-14h-42.1a5 5 0 1 1 0-2H226v18h-16v80h-12.1zm86.2-210a5 5 0 1 1 0 2H272V0h2v32h10.1zM98 101.9V146H53.9a5 5 0 1 1 0-2H96v-42.1a5 5 0 1 1 2 0zM53.9 34a5 5 0 1 1 0-2H80V0h2v34H53.9zm60.1 3.9V66H82v64H69.9a5 5 0 1 1 0-2H80V64h32V37.9a5 5 0 1 1 2 0zM101.9 82a5 5 0 1 1 0-2H128V37.9a5 5 0 1 1 2 0V82h-28.1zm16-64a5 5 0 1 1 0-2H146v44.1a5 5 0 1 1-2 0V18h-26.1zm102.2 270a5 5 0 1 1 0 2H98v14h-2v-16h124.1zM242 149.9V160h16v34h-16v62h48v48h-2v-46h-48v-66h16v-30h-16v-12.1a5 5 0 1 1 2 0zM53.9 18a5 5 0 1 1 0-2H64V2H48V0h18v18H53.9zm112 32a5 5 0 1 1 0-2H192V0h50v2h-48v48h-28.1zm-48-48a5 5 0 0 1-9.8-2h2.07a3 3 0 1 0 5.66 0H178v34h-18V21.9a5 5 0 1 1 2 0V32h14V2h-58.1zm0 96a5 5 0 1 1 0-2H137l32-32h39V21.9a5 5 0 1 1 2 0V66h-40.17l-32 32H117.9zm28.1 90.1a5 5 0 1 1-2 0v-76.51L175.59 80H224V21.9a5 5 0 1 1 2 0V82h-49.59L146 112.41v75.69zm16 32a5 5 0 1 1-2 0v-99.51L184.59 96H300.1a5 5 0 0 1 3.9-3.9v2.07a3 3 0 0 0 0 5.66v2.07a5 5 0 0 1-3.9-3.9H185.41L162 121.41v98.69zm-144-64a5 5 0 1 1-2 0v-3.51l48-48V48h32V0h2v50H66v55.41l-48 48v2.69zM50 53.9v43.51l-48 48V208h26.1a5 5 0 1 1 0 2H0v-65.41l48-48V53.9a5 5 0 1 1 2 0zm-16 16V89.41l-34 34v-2.82l32-32V69.9a5 5 0 1 1 2 0zM12.1 32a5 5 0 1 1 0 2H9.41L0 43.41V40.6L8.59 32h3.51zm265.8 18a5 5 0 1 1 0-2h18.69l7.41-7.41v2.82L297.41 50H277.9zm-16 160a5 5 0 1 1 0-2H288v-71.41l16-16v2.82l-14 14V210h-28.1zm-208 32a5 5 0 1 1 0-2H64v-22.59L40.59 194H21.9a5 5 0 1 1 0-2H41.41L66 216.59V242H53.9zm150.2 14a5 5 0 1 1 0 2H96v-56.6L56.6 162H37.9a5 5 0 1 1 0-2h19.5L98 200.6V256h106.1zm-150.2 2a5 5 0 1 1 0-2H80v-46.59L48.59 178H21.9a5 5 0 1 1 0-2H49.41L82 208.59V258H53.9zM34 39.8v1.61L9.41 66H0v-2h8.59L32 40.59V0h2v39.8zM2 300.1a5 5 0 0 1 3.9 3.9H3.83A3 3 0 0 0 0 302.17V256h18v48h-2v-46H2v42.1zM34 241v63h-2v-62H0v-2h34v1zM17 18H0v-2h16V0h2v18h-1zm273-2h14v2h-16V0h2v16zm-32 273v15h-2v-14h-14v14h-2v-16h18v1zM0 92.1A5.02 5.02 0 0 1 6 97a5 5 0 0 1-6 4.9v-2.07a3 3 0 1 0 0-5.66V92.1zM80 272h2v32h-2v-32zm37.9 32h-2.07a3 3 0 0 0-5.66 0h-2.07a5 5 0 0 1 9.8 0zM5.9 0A5.02 5.02 0 0 1 0 5.9V3.83A3 3 0 0 0 3.83 0H5.9zm294.2 0h2.07A3 3 0 0 0 304 3.83V5.9a5 5 0 0 1-3.9-5.9zm3.9 300.1v2.07a3 3 0 0 0-1.83 1.83h-2.07a5 5 0 0 1 3.9-3.9zM97 100a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-48 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 96a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-144a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-96 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm96 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-32 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM49 36a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-32 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM33 68a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 240a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm80-176a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm112 176a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM17 180a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM17 84a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6z'%3E%3C/path%3E%3C/svg%3E");
}

/* --- cabeçalho ------------------------------------------------------------
   O FluentHeader pinta o fundo inteiro com --accent-fill-rest, o que satura a
   tela e apaga o logo (accent sobre accent).

   Esta regra é a mesma que o site oficial do Fluent UI Blazor aplica na própria
   documentação (classe `siteheader` em examples/Demo/Shared/wwwroot/css/site.css):
   fundo neutro e uma linha de 2px em accent embaixo. A identidade vem da linha,
   não da faixa cheia. */

.vult0-header {
    background-color: var(--neutral-layer-2) !important;
    color: var(--neutral-foreground-rest) !important;
    border-bottom: calc(var(--stroke-width) * 2px) solid var(--accent-fill-rest);
    margin-bottom: 0 !important;
    font-weight: normal;
}

.vult0-header-bar {
    width: 100%;
    max-width: 1500px;
    margin: 0 auto;
    padding: 0 calc(var(--design-unit) * 2px);
    box-sizing: border-box;
}

/* --- conteúdo ------------------------------------------------------------- */

.vult0-content {
    width: 100%;
    max-width: 1500px;
    margin: 0 auto;
    padding: calc(var(--design-unit) * 6px) calc(var(--design-unit) * 4px)
             calc(var(--design-unit) * 10px);
    box-sizing: border-box;
}

/* O .header-gutters do FluentHeader tem 24px de margem lateral (CSS isolado do
   componente), e o conteúdo não tinha: abaixo de ~1550px cada um parava numa
   borda diferente, e o fim dos cartões não batia com o último ícone do topo —
   medido em 1440, o cartão passava 16px do ícone, quando no resto das larguras
   o ícone passa o cartão em 8. Tirando os mesmos 48px, a relação é uma só em
   toda largura. No celular não: lá o conteúdo usa a tela inteira de propósito. */
@media (min-width: 701px) {
    .vult0-content {
        max-width: min(1500px, calc(100% - 48px));
    }
}

/* --- cores semânticas do swarm -------------------------------------------- */

.vult0-seed { color: var(--presence-available); font-weight: 600; }
.vult0-leech { color: var(--warning); font-weight: 600; }
.vult0-done { color: var(--info); font-weight: 600; }

/* --- linha de torrent -----------------------------------------------------
   O FluentStack cuida de espaçamento, alinhamento e quebra. Sobra apenas o que
   nenhum parâmetro de componente expressa: o título precisa poder encolher
   dentro do flex (min-width:0) e os números precisam de largura de dígito fixa
   para as colunas não dançarem entre as linhas. */

.vult0-torrent {
    padding: 12px 16px !important;
}

.vult0-torrent:hover {
    border-color: var(--accent-fill-rest);
}

/* O FluentStack vertical nasce com width:100%. Sem declarar que esta coluna é
   quem deve crescer, ela encolhia até a largura de uma letra e o título quebrava
   caractere a caractere. É o flex-grow dela que empurra a coluna da direita para
   a borda — não há FluentSpacer entre as duas.
   A base de 240px é o que faz a linha quebrar no lugar certo em tela estreita:
   com `auto` o flex encolhia o título até zero para caber a coluna da direita
   (medido em 400px: título com 15px de largura e 960 de altura), e a quebra de
   linha nunca acontecia. */
.vult0-torrent-main {
    flex: 1 1 240px;
    min-width: 0;
}

.vult0-torrent-side {
    flex: 0 0 auto;
}

.vult0-torrent-name {
    color: var(--neutral-foreground-rest);
    font-size: 16px;
    font-weight: 600;
    text-decoration: none;
    overflow-wrap: anywhere;
    margin-bottom: 4px;
}

.vult0-torrent-name:hover {
    color: var(--accent-foreground-rest);
    text-decoration: underline;
}

.vult0-size {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    min-width: 5.5rem;
    font-weight: 600 !important;
    font-variant-numeric: tabular-nums;
}

.vult0-seed span,
.vult0-leech span,
.vult0-done span {
    font-variant-numeric: tabular-nums;
}

/* O ícone acompanha a cor semântica do bloco. */
.vult0-seed svg,
.vult0-leech svg,
.vult0-done svg {
    fill: currentColor !important;
}

/* --- texto vindo do usuário ----------------------------------------------- */

.vult0-prewrap {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.vult0-break {
    overflow-wrap: anywhere;
}

.vult0-mono {
    font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
    font-size: var(--type-ramp-minus-1-font-size);
    overflow-wrap: anywhere;
}

/* Campo de MediaInfo no upload.

   O relatório vem alinhado em colunas de espaços, e em fonte proporcional as
   colunas desandam — quem cola o texto não consegue conferir o que colou.

   O ::part é necessário: o fluent-text-area declara `font-family` no controle
   dentro do shadow DOM, e uma family herdada do host perde para essa
   declaração. Autorizado pelo usuário ao pedir o campo monoespaçado. */
.vult0-mono-area::part(control) {
    font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
    font-size: var(--type-ramp-minus-1-font-size);
}

/* Lista de arquivos do torrent: rola dentro do cartão. */
.vult0-file-list {
    max-height: 24rem;
    overflow-y: auto;
}

/* Arte NFO: fonte monoespaçada e altura de linha 1.0 para não abrir frestas entre caracteres de bloco (█ ░ ▒ ▓). */
.vult0-nfo-art {
    margin: 0;
    font-family: "Cascadia Code", "Consolas", "Courier New", "Lucida Console", monospace;
    font-size: 12px;
    line-height: 1.0;
    letter-spacing: 0;
    font-variant-ligatures: none;
    white-space: pre;
    tab-size: 8;
    text-align: left;
    overflow: hidden;
}

/* --- formulários ---------------------------------------------------------- */

.vult0-form fluent-text-field,
.vult0-form fluent-text-area,
.vult0-form fluent-select,
.vult0-form fluent-search,
.vult0-form fluent-number-field {
    width: 100%;
}

.vult0-form-narrow {
    max-width: 360px;
    margin: calc(var(--design-unit) * 8px) auto;
}

/* --- seleção múltipla -----------------------------------------------------
   Autorizada pelo usuário em 21/09/2026, para o filtro de idioma da busca. O
   Fluent 4.14.4 não tem seleção múltipla que funcione em formulário GET, nem
   popover que abra sem circuito — ver o comentário do MultiSelect.razor. O
   painel flutua sob o gatilho, com os tokens de superfície flutuante do Fluent. */

.vult0-multiselect {
    position: relative;
}

.vult0-multiselect fluent-button {
    width: 100%;
}

/* O rótulo à esquerda e a seta à direita, como no select ao lado; o padrão do
   botão é centralizar tudo. É o conteúdo que cresce, e não o controle que
   espalha: o slot "start" vazio ainda conta como item, e com space-between o
   texto ficava no meio. O fundo não precisa de regra aqui: vem do BackgroundColor
   do componente (--neutral-fill-rest, igual ao --neutral-fill-input-rest do select
   nos 12 temas), que troca o hover de fundo por opacity: 0.8 — o preço aceito. */
.vult0-multiselect fluent-button::part(content) {
    flex: 1 !important;
    text-align: start !important;
}

/* width: max-content porque, absoluto, o painel encolheria até a largura do
   gatilho e quebraria "Espanhol (América Latina)" em duas linhas. */
.vult0-multiselect-painel {
    position: absolute;
    z-index: 10;
    top: calc(100% + var(--design-unit) * 2px);
    left: 0;
    min-width: 100%;
    width: max-content;
    max-width: min(320px, 90vw);
    max-height: 320px;
    overflow-y: auto;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    gap: calc(var(--design-unit) * 2px);
    padding: calc(var(--design-unit) * 2px);
    background: var(--neutral-layer-floating);
    border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-layer-rest);
    border-radius: calc(var(--layer-corner-radius) * 1px);
    box-shadow: var(--elevation-shadow-flyout);
}

/* O display: flex de cima venceria o [hidden] do navegador. */
.vult0-multiselect-painel[hidden] {
    display: none;
}

/* --- menu suspenso do cabeçalho (NavMenu) ----------------------------------
   Autorizado pelo dono do projeto (ADR 0081). O painel é um `popover` nativo:
   a folha do navegador o centraliza na tela (`inset: 0; margin: auto`) e o
   pinta com as cores do sistema, então as duas coisas são desfeitas aqui e a
   superfície é a mesma do painel do MultiSelect. O `display: flex` só vale
   aberto — solto, venceria o `display: none` com que o navegador esconde o
   popover fechado. A posição vem do menu-suspenso.js. */
.vult0-menu-suspenso {
    inset: auto;
    margin: 0;
    min-width: 160px;
    box-sizing: border-box;
    padding: calc(var(--design-unit) * 1px);
    color: var(--neutral-foreground-rest);
    background: var(--neutral-layer-floating);
    border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-layer-rest);
    border-radius: calc(var(--layer-corner-radius) * 1px);
    box-shadow: var(--elevation-shadow-flyout);
}

.vult0-menu-suspenso:popover-open {
    display: flex;
    flex-direction: column;
}

/* Aberto, o gatilho fica com o fundo do hover, como no menu do Fluent. Não dá
   para trocar o --neutral-fill-stealth-rest como o resto do cabeçalho: ele está
   no `style` do botão com !important, e importante inline vence o da folha. O
   `aria-expanded` quem mantém é o menu-suspenso.js. */
[data-menu-suspenso][aria-expanded="true"]::part(control) {
    background: var(--neutral-fill-stealth-hover);
}

/* O conteúdo do fluent-anchor vem centralizado; num item de menu ele encosta
   à esquerda, com o ícone alinhado ao dos outros. */
.vult0-menu-suspenso fluent-anchor::part(control) {
    justify-content: flex-start;
}

/* --- busca de título (ADR 0082) ------------------------------------------
   Paleta de busca sobre o fluent-dialog. O FAST centraliza a caixa por
   `margin: auto` no `.control`, e com a altura seguindo os resultados ela
   pularia a cada resposta: aqui ela fica presa perto do topo e cresce para
   baixo. O padding sai porque o campo e a lista vão de borda a borda, com o
   divisor entre eles. `!important` porque o `::part` disputa com a folha do
   próprio componente. */
.vult0-busca::part(control) {
    margin-top: 12vh !important;
    margin-bottom: auto !important;
    padding: 0 !important;
    overflow: hidden;
}

/* O resultado é um link de bloco inteiro, com a capa e o texto dentro. O
   aceso (`data-ativo`) é o que o Enter abre: as setas e o ponteiro o movem,
   e o foco continua no campo — por isso ele não é o `:focus`. O tom é o do
   item aceso do cabeçalho. A cor repetida no `:hover` é porque o `a:hover`
   do Fluent vence uma classe sozinha. */
.vult0-busca-item {
    display: block;
    padding: 8px 12px;
    border-radius: calc(var(--control-corner-radius) * 1px);
    color: inherit;
    text-decoration: none;
}

.vult0-busca-item:hover {
    color: inherit;
}

.vult0-busca-item[data-ativo] {
    background: color-mix(in srgb, var(--accent-fill-rest) 20%, transparent);
}

@media (max-width: 700px) {
    .vult0-hide-sm {
        display: none;
    }
}

/* --- toast ----------------------------------------------------------------
   Reproduz o visual do FluentToast, que não dá para usar aqui: o componente
   exige o FluentToastProvider, que responde a eventos com StateHasChanged e
   portanto precisa de circuito. Em SSR estático quem manda a mensagem é o
   servidor, no HTML da própria resposta.

   Os valores vêm do FluentToast.razor.css da biblioteca — mesmos design tokens,
   nenhuma cor própria. Ver docs/adr/0013-toast-em-ssr.md.                     */

.vult0-toast-area {
    position: fixed;
    bottom: calc(var(--design-unit) * 6px);
    right: calc(var(--design-unit) * 6px);
    z-index: 100;
    display: flex;
    flex-direction: column;
    gap: calc(var(--design-unit) * 2px);
    /* A área cobre o canto inteiro; só os toasts recebem clique. */
    pointer-events: none;
}

.vult0-toast {
    pointer-events: auto;
    min-width: 292px;
    max-width: 500px;
    min-height: 44px;
    padding: calc(var(--design-unit) * 3px);
    background-color: var(--neutral-layer-floating);
    color: var(--neutral-foreground-rest);
    box-shadow: var(--elevation-shadow-tooltip);
    border-radius: calc(var(--control-corner-radius) * 1px);
    overflow-wrap: anywhere;
    /* Entra deslizando e sai sozinho. O `forwards` segura o estado final, senão
       o toast reaparece quando a animação termina. */
    animation: vult0-toast-in 0.3s ease-out, vult0-toast-out 0.4s ease-in 6s forwards;
}

@keyframes vult0-toast-in {
    from {
        opacity: 0;
        transform: translateY(calc(var(--design-unit) * 2px));
    }
}

@keyframes vult0-toast-out {
    to {
        opacity: 0;
        visibility: hidden;
    }
}

/* Quem pediu menos movimento continua vendo a mensagem, sem deslize nem
   desaparecimento automático — some só na próxima navegação. */
@media (prefers-reduced-motion: reduce) {
    .vult0-toast {
        animation: none;
    }
}

@media (max-width: 700px) {
    .vult0-toast-area {
        left: calc(var(--design-unit) * 3px);
        right: calc(var(--design-unit) * 3px);
        bottom: calc(var(--design-unit) * 3px);
    }

    .vult0-toast {
        min-width: 0;
        max-width: none;
    }
}

/* --- capas ----------------------------------------------------------------
   A capa e o ícone de categoria ocupam a mesma caixa: sem isso a linha muda de
   altura entre um torrent com imagem e outro sem, e a lista fica serrilhada.
   Proporção 2:3, que é a dos pôsteres que o provedor entrega.               */

.vult0-capa-mini {
    flex: 0 0 auto;
    width: 72px;
    height: 108px;
    border-radius: calc(var(--control-corner-radius) * 1px);
    object-fit: cover;
    background-color: var(--neutral-layer-floating);
}

.vult0-capa-vazia {
    display: grid;
    place-items: center;
}

/* --- cabecalho da obra ----------------------------------------------------
   Capa a esquerda, ficha a direita, arte da obra ao fundo. O `position:
   relative` e o `isolation` prendem a arte dentro do bloco: sem eles o
   pseudo-elemento escaparia para tras dos irmaos.                            */

.vult0-obra {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    /* O FluentStack em volta alinha os filhos em start: sem declarar largura, o
       bloco encolhe ate o conteudo e fica menor que os cartoes abaixo. */
    width: 100%;
    box-sizing: border-box;
    display: flex;
    align-items: stretch;
    gap: calc(var(--design-unit) * 5px);
    padding: calc(var(--design-unit) * 5px);
    border-radius: calc(var(--control-corner-radius) * 2px);
    background-color: var(--neutral-layer-card-container);
    border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);
}

/* A arte entra num pseudo-elemento, e nao como background do bloco, porque
   precisa de desfoque e opacidade proprios — aplica-los no bloco levaria o
   texto junto. */
.vult0-obra-arte::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background-image: var(--vult0-arte);
    background-size: cover;
    background-position: center 20%;
    filter: blur(4px);
    opacity: 0.2;
}

/* O gradiente devolve contraste ao texto sobre a parte clara da arte. */
.vult0-obra-arte::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(
        to right,
        var(--neutral-layer-card-container) 0%,
        transparent 100%);
    opacity: 0.85;
}

/* align-self: sem ele o item herda o stretch do flex e cresce até a altura do
   cartão, que passa dos 300px quando a sinopse é longa — medido, 200x403 num
   jogo do IGDB, com o cover cortando as laterais. Com a altura esticada o
   aspect-ratio deixa de valer. */
.vult0-obra-capa {
    flex: 0 0 auto;
    align-self: flex-start;
    width: 200px;
    aspect-ratio: 2 / 3;
    border-radius: calc(var(--control-corner-radius) * 1px);
    object-fit: cover;
    background-color: var(--neutral-layer-floating);
    box-shadow: var(--elevation-shadow-card-rest);
}

.vult0-obra-capa-vazia {
    display: grid;
    place-items: center;
}

/* min-width: 0 para o titulo poder encolher dentro do flex em vez de empurrar
   a capa para fora. */
.vult0-obra-ficha {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: calc(var(--design-unit) * 2px);
    min-height: 0;
}

/* A sinopse para de crescer antes da linha ficar longa demais para ler. */
.vult0-obra-sinopse {
    max-width: 80ch;
    opacity: 0.85;
}

/* A barra de acoes e a sinopse seguem a mesma regra: o pai alinha em start. */
.vult0-obra-ficha > * {
    max-width: 100%;
}

/* --- linha do release -----------------------------------------------------
   Nome tecnico e metadados a esquerda, acao a direita, separados do bloco da
   obra por uma linha — e o ponto em que a ficha da obra vira o arquivo.      */

.vult0-release {
    display: flex;
    align-items: center;
    gap: calc(var(--design-unit) * 3px);
    margin-top: calc(var(--design-unit) * 5px);
    padding-top: calc(var(--design-unit) * 3px);
    border-top: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);
}

.vult0-release-texto {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: calc(var(--design-unit) * 1px);
}

.vult0-release-nome {
    font-weight: 600;
}

@media (max-width: 700px) {
    .vult0-obra {
        flex-direction: column;
    }

    .vult0-obra-capa {
        width: 130px;
        align-self: center;
    }

    .vult0-release {
        flex-direction: column;
        align-items: stretch;
    }
}

/* --- toast ----------------------------------------------------------------
   Reproduz o visual do FluentToast, que não dá para usar aqui: o componente
   exige o FluentToastProvider, que responde a eventos com StateHasChanged e
   portanto precisa de circuito. Em SSR estático quem manda a mensagem é o
   servidor, no HTML da própria resposta.

   Os valores vêm do FluentToast.razor.css da biblioteca — mesmos design tokens,
   nenhuma cor própria. Ver docs/adr/0013-toast-em-ssr.md.                     */

.vult0-toast-area {
    position: fixed;
    bottom: calc(var(--design-unit) * 6px);
    right: calc(var(--design-unit) * 6px);
    z-index: 100;
    display: flex;
    flex-direction: column;
    gap: calc(var(--design-unit) * 2px);
    /* A área cobre o canto inteiro; só os toasts recebem clique. */
    pointer-events: none;
}

.vult0-toast {
    pointer-events: auto;
    min-width: 292px;
    max-width: 500px;
    min-height: 44px;
    padding: calc(var(--design-unit) * 3px);
    background-color: var(--neutral-layer-floating);
    color: var(--neutral-foreground-rest);
    box-shadow: var(--elevation-shadow-tooltip);
    border-radius: calc(var(--control-corner-radius) * 1px);
    overflow-wrap: anywhere;
    /* Entra deslizando e sai sozinho. O `forwards` segura o estado final, senão
       o toast reaparece quando a animação termina. */
    animation: vult0-toast-in 0.3s ease-out, vult0-toast-out 0.4s ease-in 6s forwards;
}

@keyframes vult0-toast-in {
    from {
        opacity: 0;
        transform: translateY(calc(var(--design-unit) * 2px));
    }
}

@keyframes vult0-toast-out {
    to {
        opacity: 0;
        visibility: hidden;
    }
}

/* Quem pediu menos movimento continua vendo a mensagem, sem deslize nem
   desaparecimento automático — some só na próxima navegação. */
@media (prefers-reduced-motion: reduce) {
    .vult0-toast {
        animation: none;
    }
}

@media (max-width: 700px) {
    .vult0-toast-area {
        left: calc(var(--design-unit) * 3px);
        right: calc(var(--design-unit) * 3px);
        bottom: calc(var(--design-unit) * 3px);
    }

    .vult0-toast {
        min-width: 0;
        max-width: none;
    }
}

/* --- capas ----------------------------------------------------------------
   A capa e o ícone de categoria ocupam a mesma caixa: sem isso a linha muda de
   altura entre um torrent com imagem e outro sem, e a lista fica serrilhada.
   Proporção 2:3, que é a dos pôsteres que o provedor entrega.               */

.vult0-capa-mini {
    flex: 0 0 auto;
    width: 72px;
    height: 108px;
    border-radius: calc(var(--control-corner-radius) * 1px);
    object-fit: cover;
    background-color: var(--neutral-layer-floating);
}

.vult0-capa-vazia {
    display: grid;
    place-items: center;
}

/* --- ficha da obra --------------------------------------------------------
   Capa à esquerda, dados à direita, e a arte da obra ao fundo. O `position:
   relative` e o `isolation` prendem a arte dentro do cartão: sem eles o
   pseudo-elemento escaparia para trás dos irmãos.                            */

.vult0-ficha {
    position: relative;
    isolation: isolate;
    overflow: hidden;
}

/* A arte entra num pseudo-elemento, e não como background do cartão, porque
   precisa de desfoque e opacidade próprios — aplicá-los no cartão levaria o
   texto junto. */
.vult0-ficha-arte::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background-image: var(--vult0-arte);
    background-size: cover;
    background-position: center 20%;
    filter: blur(4px);
    opacity: 0.2;
}

/* O gradiente devolve contraste ao texto sobre a parte clara da arte. */
.vult0-ficha-arte::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(
        to right,
        var(--neutral-layer-card-container) 0%,
        transparent 60%,
        transparent 100%);
    opacity: 0.75;
}

.vult0-ficha-conteudo {
    display: flex;
    align-items: flex-start;
    gap: calc(var(--design-unit) * 4px);
}

.vult0-ficha-capa {
    flex: 0 0 auto;
    width: 150px;
    aspect-ratio: 2 / 3;
    border-radius: calc(var(--control-corner-radius) * 1px);
    object-fit: cover;
    background-color: var(--neutral-layer-floating);
    box-shadow: var(--elevation-shadow-card-rest);
}

/* Numa tela estreita a capa e os dados empilham, senão sobra uma coluna de
   texto de poucos caracteres. */
@media (max-width: 700px) {
    .vult0-ficha-conteudo {
        flex-direction: column;
    }

    .vult0-ficha-capa {
        width: 120px;
        align-self: center;
    }
}

/* O rodapé mora no fim da área que rola (MainLayout), e não preso ao pé da
   tela, onde cobria o conteúdo. Coluna com o conteúdo crescendo é o que o
   empurra para o fundo quando a página é curta: sem isso ele ficava solto no
   meio da tela, medido em y=730 de 900 nas configurações. */
.body-content:has(> .vult0-footer) {
    display: flex;
    flex-direction: column;
}

.body-content:has(> .vult0-footer) > .vult0-content {
    flex: 1 0 auto;
}

/* Na coluna o rodapé encolhia até o texto (466px medidos). */
.body-content > .vult0-footer {
    width: 100%;
    box-sizing: border-box;
}

/* O FluentFooter também pinta o fundo em accent, como o header — mesma razão e
   mesmo tratamento da classe vult0-header. */
.vult0-footer {
    background-color: var(--neutral-layer-4) !important;
    color: var(--neutral-foreground-rest) !important;
    border-top: 1px solid var(--neutral-stroke-divider-rest);
    justify-content: center;
    padding: calc(var(--design-unit) * 3px);
    font-weight: normal;
}

/* --- pills (Shared/PillNav.razor) ------------------------------------------
   Pill apagada: mais fraca em repouso e plena sob o cursor ou o
   foco. Ela não tem fundo em estado nenhum (os tokens de fundo são apagados no
   Style do PillNavItem), então é a opacidade que responde — e ela vai aqui
   porque estilo inline não alcança :hover. O :focus-within dá a quem navega por
   Tab o mesmo retorno de quem usa o mouse; o foco do fluent-anchor fica no <a>
   do shadow DOM, e é isso que o :focus-within enxerga pelo hospedeiro. */
.vult0-pill:not([aria-current]) {
    opacity: 0.7;
}

.vult0-pill:not([aria-current]):hover,
.vult0-pill:not([aria-current]):focus-within {
    opacity: 1;
}

/* --- sala de conversa -----------------------------------------------------
   Nenhum componente Fluent cobre a casca de um chat: histórico rolando preso
   ao rodapé e caixa de envio embaixo. O que dá para compor com componente foi
   composto — as salas são o PillNav no cabeçalho, o autor é FluentPersona, a
   caixa é FluentTextArea. Só a geometria mora aqui, e toda
   cor sai de token.                                                          */

/* A sala é a única superfície afundada do site (--neutral-layer-3, abaixo do
   fundo da página), e de propósito: todo o resto que se lê fica elevado na cor
   do cartão, e a sala é a área que muda sozinha e recebe o que se digita. As
   bolhas, a citação e a linha do mural sobem para a cor do cartão sobre ela. */
.vult0-chat {
    display: flex;
    width: 100%;
    box-sizing: border-box;
    /* Altura fixa de propósito: sem ela o histórico empurraria a lista de
       torrents para fora da primeira tela conforme a conversa crescesse. */
    height: 600px;
    overflow: hidden;
    /* Bloco de referencia do aviso de queda do fluxo, que cobre o painel
       inteiro com `inset: 0`. */
    position: relative;
    border-radius: calc(var(--control-corner-radius) * 2px);
    border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);
    background-color: var(--neutral-layer-3);
}

/* Aviso de queda do fluxo. Acima da paleta (3) e da barra de acoes (2), que
   ficam inertes enquanto ele esta na tela.

   A transparencia esta na COR e nao em `opacity`: opacidade no elemento apaga
   junto o anel e o texto, que sao justamente o que precisa ser lido — medido, o
   rotulo saia lavado sobre o fundo escuro. */
.vult0-chat-reconnect-overlay {
    position: absolute;
    inset: 0;
    z-index: 10;
    background-color: color-mix(in srgb, var(--neutral-layer-card-container) 85%, transparent);
    display: flex;
    align-items: center;
    justify-content: center;
}

.vult0-chat-reconnect-overlay[hidden] {
    display: none;
}

/* Um bloco por estado — "reconectando" e "caiu de vez" —, alternados pelo
   salas.js. O `[hidden]` precisa de regra propria porque o display vem daqui e
   vence o do agente do usuario; e a mesma razao de `.vult0-chat-paleta [hidden]`. */
.vult0-chat-reconnect-estado {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: calc(var(--design-unit) * 3px);
}

.vult0-chat-reconnect-estado[hidden] {
    display: none;
}

/* min-width para o histórico poder encolher em vez de esticar a casca;
   min-height pelo mesmo motivo no outro eixo — sem ele o corpo passava da
   altura e o overflow: hidden comia a caixa de envio. Medido. */
.vult0-chat-corpo {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.vult0-chat-cabecalho {
    flex: 0 0 auto;
    padding: calc(var(--design-unit) * 2px) calc(var(--design-unit) * 3px);
    border-bottom: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);
    background: var(--neutral-layer-2);
}

.vult0-chat-historico {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    /* A barra única de ações é posicionada aqui dentro, sobre a mensagem sob o
       cursor: o relative faz o histórico ser o bloco de referência, e o absolute
       rola junto com o conteúdo. */
    position: relative;
}

.vult0-chat-mensagem {
    display: flex;
    flex-direction: row;
    align-items: flex-end;
    gap: calc(var(--design-unit) * 1.5px);
    align-self: flex-start;
    margin: 8px 120px 0 10px;
    max-width: calc(100% - 130px);
}

/* A mensagem que continua a sequência da mesma pessoa encosta na anterior,
   como no Telegram: o vão de 8px fica só entre pessoas diferentes, e é ele
   que mostra onde muda quem fala. */
.vult0-chat-mensagem[data-continua] {
    margin-top: 2px;
}

/* Sem altura própria: a linha da mensagem mede o que a bolha mede. Com os
   44px do avatar, toda bolha de uma linha (33px) ganhava 11px de vão, e a
   conversa ficava espaçada. O avatar se ancora na base da bolha, 8px acima
   dela, e o que passa da altura sobe para a margem entre as mensagens. */
.vult0-chat-avatar-slot {
    width: 44px;
    height: 0;
    padding-bottom: 8px;
    align-self: flex-end;
    flex: 0 0 44px;
    display: flex;
    align-items: flex-end;
    justify-content: center;
}

.vult0-chat-avatar-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
}

/* O fator 1.155 amplia o avatar base de 28px para ~32.34px, preenchendo
   proporcionalmente o slot de 44x44 e casando com a moldura de 38x38. */
.vult0-chat-avatar-slot .vult0-avatar,
.vult0-chat-avatar-slot .fluent-persona {
    transform: scale(1.155);
}

.vult0-chat-avatar-slot .fluent-persona {
    display: flex;
    width: 28px;
    height: 28px;
    border-radius: 999px;
    align-items: center;
    justify-content: center;
    white-space: nowrap;
}

.vult0-chat-avatar-slot .initials {
    display: flex;
    width: 28px;
    height: 28px;
    color: var(--neutral-foreground-rest);
    background: transparent;
    font-weight: 600;
    border-radius: 50%;
    text-align: center;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1 / 1;
    overflow: hidden;
}

.vult0-chat-avatar-slot .fluent-presence-badge {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
}

.vult0-chat-avatar-slot .initials img {
    border-radius: 50%;
    aspect-ratio: 1 / 1;
    width: 28px;
    height: 28px;
    display: block;
    object-fit: cover;
}

.vult0-chat-conteudo {
    display: flex;
    flex-direction: column;
    gap: calc(var(--design-unit) * 0.5px);
    padding: 6px 12px;
    background-color: var(--neutral-layer-1);
    border-radius: 8px;
    min-width: 0;
}

.vult0-chat-autor {
    font-weight: 600;
    color: var(--accent-foreground-rest);
    text-decoration: none;
}

.vult0-chat-autor:hover {
    text-decoration: underline;
}

/* Mesma aparência no que o Razor desenha e no que o chat.js acrescenta: se as
   duas divergirem, a mensagem muda de cara ao recarregar a página. */
.vult0-chat-quando {
    color: var(--neutral-foreground-hint);
    font-size: var(--type-ramp-minus-1-font-size);
}

/* Mesma regra do comentário: preserva a quebra de linha que a pessoa digitou e
   deixa palavra longa quebrar em vez de esticar a caixa. */
.vult0-chat-texto {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    /* Contém o horário flutuante abaixo, que senão vazaria da bolha. */
    display: flow-root;
}

/* O horário da mensagem, no canto inferior direito da bolha, como no Telegram.
   Ele vem por último dentro do texto e flutua à direita: cabe na última linha,
   fica nela; não cabe, desce para uma linha própria, ainda à direita. O
   margin-top o assenta na base da linha em vez do topo, e é em px para não
   crescer com a fonte da mensagem só de emoji. */
.vult0-chat-hora {
    float: right;
    margin: 5px -4px 0 12px;
    font-size: var(--type-ramp-minus-1-font-size);
    line-height: var(--type-ramp-minus-1-line-height);
    font-variant-numeric: tabular-nums;
    color: var(--neutral-foreground-hint);
    white-space: nowrap;
}

/* Com reação, o horário desce para a linha dela, à direita, como no Telegram —
   em cima dela ele ficava solto numa linha a mais. É CSS e não o salas.js
   movendo o nó porque a reação chega pelo fluxo depois da mensagem, e some
   quando a última é tirada: o :has acompanha os dois sem ninguém avisar. A
   fileira reserva à direita a largura do horário, que sai do fluxo do texto. */
.vult0-chat-conteudo:has(> .vult0-chat-reacoes:not(:empty)) {
    position: relative;
}

.vult0-chat-conteudo:has(> .vult0-chat-reacoes:not(:empty)) .vult0-chat-hora {
    position: absolute;
    right: 8px;
    bottom: 9px;
    float: none;
    margin: 0;
}

.vult0-chat-conteudo > .vult0-chat-reacoes:not(:empty) {
    padding-right: 44px;
}

/* Quando a mensagem contém apenas emojis, o tamanho aumenta 20%. */
.vult0-chat-texto-emoji {
    font-size: 1.4em;
    margin: 4px -2px 5px;
}

.vult0-chat-envio {
    flex: 0 0 auto;
    padding: calc(var(--design-unit) * 2px) calc(var(--design-unit) * 3px);
    /*border-top: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);*/
}

/* A scrollbar da caixa de envio vive no shadow do fluent-text-area: o
   <textarea> é o part="control", e não existe componente que a esconda. A caixa
   cresce até 4 linhas e, além disso, o texto rola dentro dela — quem rola
   continua funcionando (mouse/teclado); só a barra some. */
.vult0-chat-envio fluent-text-area::part(control) {
    scrollbar-width: none;
}

.vult0-chat-envio fluent-text-area::part(control)::-webkit-scrollbar {
    display: none;
}

/* Linha do mural: barra colorida à esquerda, como na referência, para o olho
   separar as linhas sem precisar de borda em volta de cada uma. */
.vult0-mural-linha {
    display: flex;
    align-items: center;
    gap: calc(var(--design-unit) * 2px);
    padding: calc(var(--design-unit) * 1.5px) calc(var(--design-unit) * 2px);
    border-left: calc(var(--stroke-width) * 3px) solid var(--accent-fill-rest);
    border-radius: calc(var(--control-corner-radius) * 1px);
    background-color: var(--neutral-layer-1);
    margin: 8px 12px 0 12px;
}

/* min-width: 0 para o nome do release quebrar em vez de esticar a linha. */
.vult0-mural-texto {
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: anywhere;
}

.vult0-mural-alvo {
    color: var(--neutral-foreground-rest);
    font-weight: 600;
    text-decoration: none;
}

.vult0-mural-alvo:hover {
    color: var(--accent-foreground-rest);
    text-decoration: underline;
}

/* Citação acima da resposta: barra em accent à esquerda, como a linha do mural,
   para o olho separar num relance o que foi citado do que está sendo dito. */
.vult0-chat-citacao {
    display: flex;
    flex-direction: column;
    align-items: baseline;
    align-self: flex-start;
    max-width: 100%;
    padding: 4px 8px;
    margin: 2px 0 2px -2px;
    border-left: calc(var(--stroke-width) * 3px) solid var(--accent-fill-rest);
    border-radius: calc(var(--control-corner-radius) * 1px);
    background-color: var(--neutral-layer-2);
    font-size: var(--type-ramp-minus-1-font-size);
    color: var(--neutral-foreground-hint);
    text-decoration: none;
    line-height: 1.4;
}

.vult0-chat-citacao:hover {
    background-color: var(--neutral-fill-secondary-hover);
}

.vult0-chat-citacao-autor {
    font-weight: 600;
    color: var(--accent-foreground-rest);
    white-space: nowrap;
}

/* Uma linha só: a citação lembra o que foi dito, não repete a mensagem.
   O max-width é o que faz o corte acontecer: a citação é flex em coluna, e
   nesse eixo o filho fica com a largura do próprio texto em nowrap — o
   min-width: 0 só vale no eixo principal. Sem ele, em 400px o trecho media
   658px numa caixa de 162, atravessava a borda sem reticências e dava
   rolagem lateral ao histórico inteiro. */
.vult0-chat-citacao-texto {
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* --- comentários da ficha do torrent --------------------------------------
   Deliberadamente **não** reusam nada da sala acima. Lá a conversa é rápida e
   as mensagens são bolhas empilhadas; aqui o que se lê é texto, e a resposta
   fica indentada sob o que ela responde — a posição conta a quem se responde, e
   por isso a citação não repete o texto citado.                              */

/* A linha vertical que desce do avatar de um comentário até as respostas dele.

   Elemento de verdade no HTML, e não um pseudo-elemento: a curva já ocupa o
   `::before` do mesmo `div`, e um elemento tem um `::before` só — declaradas
   nas duas classes, as regras colidiam num híbrido, e o que se via era a linha
   com o traço da curva e a curva sumida nos comentários que tinham resposta.

   O `left` é medido: é o **centro do retrato** (28px, logo 14), e não o da
   moldura, que é sobreposta e se estende para fora dele. Em cima ela nasce no
   topo do ramo, e quem a esconde até o queixo é o próprio avatar, opaco; embaixo
   ela vai até o fim, porque quem decide onde ela para é a tarja do último filho.
   Havia aqui um `bottom: 80px` chutado, e ele só acertava com resposta de uma
   linha: medido, com a resposta mais alta a linha passava da curva, e com uma
   mais baixa que 94px pararia antes dela.                                      */
.vult0-comentario-linha {
    position: absolute;
    left: calc(var(--design-unit) * 3.5px);
    top: 0;
    bottom: 0;
    border-left: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);
    z-index: -1;
}

/* A curva que liga cada resposta à linha do comentário respondido, como no
   Reddit: um "L" de cantos arredondados que sai da vertical do pai e aponta
   para o avatar da resposta.

   Os números saem da geometria do degrau, e não de um token: o conteúdo do fio
   começa 32px à direita da borda do ramo (12 de margem e 20 de preenchimento)
   e a vertical do pai está a 14 dela — logo a curva volta 18px para encontrá-la.
   A altura é a metade do avatar, que é onde a linha deve apontar.

   O `>` em cada passo é o que impede a curva de vazar para os netos: a cada
   nível, só o filho direto do degrau daquele nível a recebe.

   E o `z-index`: a tarja que corta a linha do pai começa onde o **arco** começa,
   então dali para baixo ela cobre a própria curva. Um degrau acima devolve o
   desenho — e o degrau é preciso mesmo com a curva sendo `::before` e a tarja
   `::after`, porque entre pseudo-elementos do mesmo nó quem vem depois pinta
   por cima.                                                                    */
.vult0-comentario-ramo {
    position: relative;
}

.vult0-comentario-fio > div > .vult0-comentario-ramo::before {
    content: "";
    position: absolute;
    z-index: 1;
    left: calc(var(--design-unit) * -4.5px);
    top: 0;
    width: calc(var(--design-unit) * 4px);
    height: calc(var(--design-unit) * 3.5px);
    border-left: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);
    border-bottom: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);
    border-bottom-left-radius: calc(var(--control-corner-radius) * 2px);
}

/* A linha do comentário termina na **última resposta direta** dele, e não no
   fim de tudo que pende dela: da curva daquela resposta para baixo, o que
   houver de vertical pertence à subárvore dela, não a esta.

   Corta cobrindo, e não encurtando: o elemento que desenha a linha envolve a
   subárvore inteira, e onde ela deve parar é a curva do último filho — uma
   altura que só o navegador conhece e que nenhum `calc` alcança. A cor é
   `--fill-color` porque é o token que o próprio `fluent-card` computa para o
   fundo em que a linha é pintada; medido, `rgb(39, 39, 39)` nos dois.

   O corte começa onde o **arco** começa, e não onde ele termina: a curva deixa a
   vertical um raio acima do canto (14 − 8 = 6px, medido), e cortando só embaixo
   a reta do pai atravessava o arco e sobrava por baixo dele — os 8px que se
   viam passando da curva. Daqui para baixo a tarja cobre também o arco, e quem
   o devolve é o `z-index` da regra acima.

   A largura passa de 1px de propósito, para cobrir a borda inteira sem deixar
   fiapo, e o `bottom` negativo passa do vão entre irmãos.                      */
.vult0-comentario-fio > div > .vult0-comentario-ramo:last-child::after {
    content: "";
    position: absolute;
    left: calc(var(--design-unit) * -5px);
    top: calc(var(--design-unit) * 3.5px - var(--control-corner-radius) * 2px);
    bottom: calc(var(--design-unit) * -5px);
    width: calc(var(--design-unit) * 1.5px);
    background: var(--fill-color);
}

/* O degrau das respostas. Só o recuo: quem desenha a linha e a curva são o
   `span` do ramo e o `::before` de cada filho. */
.vult0-comentario-fio {
    width: calc(100% - calc(var(--design-unit) * 3.5px));
    margin-left: calc(var(--design-unit) * 3px);
    padding-left: calc(var(--design-unit) * 5px);
}

/* Uma linha só, e só o nome: o texto citado está a poucos pixels daqui, dentro
   do mesmo fio. Só aparece na resposta a outra resposta, onde a posição não
   distingue quem respondeu a quem. */
.vult0-comentario-citacao {
    align-self: flex-start;
    font-size: var(--type-ramp-minus-1-font-size);
    color: var(--neutral-foreground-hint);
    text-decoration: none;
}

/* A cor é repetida no hover porque a folha do Fluent traz um `a:hover` mais
   específico que uma classe. */
.vult0-comentario-citacao:hover {
    color: var(--accent-foreground-rest);
    text-decoration: underline;
}

/* O rodapé de ações. Só o arranjo mora aqui: a aparência apagada de cada botão
   é token no `style` **do próprio botão**, e não neste invólucro — os temas
   gerados declaram os mesmos tokens em `* { … !important }`, e esse `*` casa
   direto com o botão, vencendo qualquer herança que viesse daqui. Medido: com
   os tokens no invólucro, o `.control` continuava em `rgb(39,39,39)` e 14px. */
.vult0-comentario-acoes {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    /* Puxa o texto do primeiro botão para a coluna do corpo: o `.control` do
       fluent-button tem preenchimento próprio, e sem isto as ações nasciam
       recuadas em relação ao comentário. */
    margin-left: calc(var(--design-unit) * -2.5px);
}

/* A fileira existe mesmo vazia, porque é onde o salas.js escreve o que chega
   pelo fluxo; :empty é o que impede a caixa de crescer sem reação nenhuma. */
.vult0-chat-reacoes {
    display: flex;
    flex-wrap: wrap;
    gap: calc(var(--design-unit) * 1px);
    margin-top: calc(var(--design-unit) * 1px);
    margin-left: -2px;
}

.vult0-chat-reacoes:empty {
    display: none;
}

/* Botao, e nao link: o chip age em vez de navegar. Herdar a fonte e o que o
   impede de sair no tipo do sistema. */
.vult0-chat-reacao {
    font-family: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: calc(var(--design-unit) * 1px);
    padding: 0 calc(var(--design-unit) * 1.5px);
    border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-rest);
    border-radius: calc(var(--control-corner-radius) * 3px);
    background-color: var(--neutral-layer-2);
    font-size: var(--type-ramp-minus-1-font-size);
    line-height: calc(var(--design-unit) * 5px);
    color: var(--neutral-foreground-rest);
    text-decoration: none;
}

/* O `a:hover` da folha do Fluent tem especificidade maior que uma classe e
   repinta o texto em accent — sobre o chip aceso isso e claro sobre claro, e o
   numero some. Medido; por isso as duas regras dizem a cor de novo. */
.vult0-chat-reacao:hover {
    border-color: var(--accent-fill-rest);
    color: var(--neutral-foreground-rest);
}

.vult0-chat-reacao-minha:hover {
    color: var(--accent-fill-rest);
}

/* Aceso é o chip de quem já reagiu — é o que diz onde o clique desfaz. */
.vult0-chat-reacao-minha {
    border-color: var(--accent-fill-rest);
    background-color: color-mix(in srgb, var(--accent-fill-rest) 20%, transparent);
    color: var(--accent-fill-rest);
}

.vult0-chat-reacao-conta {
    font-variant-numeric: tabular-nums;
}

/* A paleta é desenhada pelo cliente a partir do molde que o Razor manda. Abre
   abaixo e à direita da barra, mas ancorada no histórico — não na barra, que
   pode ir para outra mensagem sem fechar a paleta. O salas.js a prende dentro
   do histórico com `top`/`left` em pixels quando ela não cabe nessa direção
   (vira para cima ou para a esquerda, e no meio do histórico fica
   centralizada). A caixa de busca no topo e a grade rolável embaixo. */
.vult0-chat-paleta {
    position: absolute;
    top: calc(100% + calc(var(--design-unit) * 1px));
    left: calc(100% + calc(var(--design-unit) * 1px));
    z-index: 3;
    width: 280px;
    display: flex;
    flex-direction: column;
    gap: calc(var(--design-unit) * 1px);
    padding: calc(var(--design-unit) * 1px);
    background-color: var(--neutral-layer-floating);
    box-shadow: var(--elevation-shadow-tooltip);
    border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);
    border-radius: calc(var(--control-corner-radius) * 1px);
}

/* A grade de emojis: 8 por linha, com rolagem própria quando o catálogo não
   cabe (56 emojis dão sete linhas). */
.vult0-chat-paleta-grade {
    display: grid;
    grid-template-columns: repeat(8, 32px);
    gap: calc(var(--design-unit) * 0.5px);
    max-height: 260px;
    overflow-y: auto;
}

.vult0-chat-paleta [data-emoji] {
    width: 32px;
    height: 32px;
    min-width: 0;
    padding: 0;
}

/* O botão interno do Fluent (::part(control)) traz `padding: 0 10px` próprio,
   que empurra o símbolo para fora do botão de 32px e o faz sobrepor o vizinho
   da esquerda. ::part não atravessa o shadow DOM — daí o !important. */
.vult0-chat-paleta [data-emoji]::part(control) {
    padding: 0 !important;
}

/* O emoji em tamanho de picker — o símbolo dos chips é menor. */
.vult0-chat-paleta .vult0-chat-reacao-simbolo {
    font-size: 20px;
    line-height: 1;
}

/* O Fluent pinta o host dos botões; o hidden do atributo precisa vencer. */
.vult0-chat-paleta [hidden] {
    display: none;
}

/* Barra única de ações: um só elemento para a sala inteira, posicionado pelo
   salas.js sobre a mensagem sob o cursor (ou em foco/toque). Absoluta dentro do
   histórico, para rolar junto com a mensagem; o translateY centra no eixo
   vertical em relação ao ponto que o script calcula. */
.vult0-chat-acoes {
    position: absolute;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: calc(var(--design-unit) * 0.5px);
    transform: translateY(-50%);
}

.vult0-chat-acoes[hidden] {
    display: none;
}

/* Faixa da citação, logo acima da caixa de envio. */
.vult0-chat-resposta-a {
    display: flex;
    align-items: center;
    gap: calc(var(--design-unit) * 1px);
    padding: 0 0 0 calc(var(--design-unit) * 2px);
    margin-bottom: calc(var(--design-unit) * 1px);
    border-left: calc(var(--stroke-width) * 3px) solid var(--accent-fill-rest);
    border-radius: calc(var(--control-corner-radius) * 1px);
    background-color: var(--neutral-layer-1);
    font-size: var(--type-ramp-minus-1-font-size);
    color: var(--neutral-foreground-hint);
    margin-right: 40px;
}

/* Cresce e encolhe o trecho, para o botão de cancelar não sair da faixa. */
.vult0-chat-resposta-a .vult0-chat-citacao-texto {
    flex: 1 1 auto;
}

@media (max-width: 700px) {
    .vult0-chat {
        height: 520px;
    }
}

/* --- decorações de avatar -------------------------------------------------
   Moldura decorativa animada sobre o avatar. Posicionada de forma absoluta
   sobre o invólucro do avatar.                                               */

.vult0-avatar {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    vertical-align: middle;
}

.vult0-avatar-decoracao {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    pointer-events: none;
}

.vult0-chat-avatar-slot .fluent-persona .initials {
    background: transparent !important;
    color: var(--neutral-foreground-rest) !important;
}

/* --- botão de seleção de arquivo estilo Fluent UI (SSR estático) -----------
   Permite estilizar o seletor de arquivo com aparência idêntica ao
   FluentButton (ícone, tokens e texto em português) sem circuito interativo. */

.vult0-file-input-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.vult0-file-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: calc(var(--design-unit) * 1.5px);
    box-sizing: border-box;
    height: calc((var(--base-height-multiplier) + var(--density)) * var(--design-unit) * 1px);
    padding: 0 calc(var(--design-unit) * 3px);
    background-color: var(--neutral-fill-rest);
    color: var(--neutral-foreground-rest);
    border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-rest);
    border-radius: calc(var(--control-corner-radius) * 1px);
    font-family: inherit;
    font-size: var(--type-ramp-base-font-size);
    font-weight: 400;
    cursor: pointer;
    user-select: none;
    transition: background-color 0.1s ease, border-color 0.1s ease, color 0.1s ease;
}

.vult0-file-button:hover {
    background-color: var(--neutral-fill-hover);
    border-color: var(--neutral-stroke-hover);
}

.vult0-file-button:active {
    background-color: var(--neutral-fill-active);
    border-color: var(--neutral-stroke-active);
}

.vult0-file-input-hidden:focus-visible + * .vult0-file-button,
.vult0-file-button:focus-visible {
    outline: calc(var(--stroke-width) * 2px) solid var(--accent-fill-rest);
    outline-offset: 1px;
}

.vult0-file-button svg {
    fill: currentColor !important;
}

.vult0-file-name {
    color: var(--neutral-foreground-hint);
    font-size: var(--type-ramp-base-font-size);
    overflow-wrap: anywhere;
}


/* Menu lateral da loja e da administração. O item em repouso é pintado com
   --neutral-fill-stealth-rest, que é a cor do cartão (#272727): sobre o fundo
   da página, cada item virava uma caixa. Transparente, só o ativo tem
   superfície — a do cartão, um degrau acima da página. O token vai no próprio
   elemento, e não no menu, porque o `*` dos temas casa com ele direto e vence
   a herança; e é token, e não `background`, para o hover do componente
   continuar valendo. */
.fluent-nav-item .positioning-region {
    --neutral-fill-stealth-rest: transparent !important;
}

.fluent-nav-link.active > .positioning-region {
    background: var(--neutral-layer-1) !important;
}
/* --- realce de sintaxe das notícias ----------------------------------------
   Autorizado pelo dono do projeto (ADR 0056). O highlight.js só escreve as
   classes; as cores são estas, e cada uma é um design token que os doze temas
   já definem — nada de tema pronto com paleta própria. Segue claro e escuro
   sozinho, ao preço de pintar menos tons do que um editor: palavra-chave no
   accent, texto em verde, número em laranja, nome em negrito, comentário apagado. */

.hljs-keyword,
.hljs-built_in,
.hljs-literal,
.hljs-type,
.hljs-selector-tag,
.hljs-doctag {
    color: var(--accent-foreground-rest);
}

.hljs-string,
.hljs-regexp,
.hljs-addition,
.hljs-attribute,
.hljs-selector-attr {
    color: var(--presence-available);
}

.hljs-number,
.hljs-symbol,
.hljs-bullet,
.hljs-variable.constant_ {
    color: var(--warning);
}

/* Nome em peso, e não em cor: o --info, que seria o azul, é o cinza #616161
   nos doze temas — medido, sumia no fundo escuro. */
.hljs-title,
.hljs-name,
.hljs-attr,
.hljs-selector-class,
.hljs-selector-id,
.hljs-property {
    color: var(--neutral-foreground-rest);
    font-weight: 600;
}

.hljs-comment,
.hljs-quote,
.hljs-meta {
    color: var(--neutral-foreground-hint);
    font-style: italic;
}

.hljs-deletion {
    color: var(--error);
}

.hljs-section,
.hljs-strong {
    font-weight: 600;
}

.hljs-emphasis {
    font-style: italic;
}

/* --- editor de Markdown ao vivo --------------------------------------------
   Autorizado pelo dono do projeto (ADR 0058). O TinyMDE escreve o texto em
   linhas com classes TM* e traz uma folha própria, de paleta fixa e clara, que
   não é carregada: quem pinta são estas regras, e só com os tokens que os doze
   temas definem. A escala dos títulos é a do FluentLabel que o MarkdownBlocks
   usa na notícia publicada (H3, H4 e H5 viram plus-3, plus-2 e plus-1) — medido,
   tamanho, altura de linha e peso batem nos dez elementos comparados.

   Os marcadores (`#`, `**`, `-`) continuam na tela, apagados: é Markdown ao
   vivo, e não WYSIWYG. Escondê-los desalinharia o cursor do texto, que é a
   string que vai para o banco.

   Até o script ligar, a caixa não existe e o fluent-text-area aparece sozinho.
   Depois, ele some e o rótulo fica: o componente desenha o rótulo como irmão
   do campo, e não dentro dele. Escondido, ele continua indo no POST — elemento
   form-associated submete pelo valor, não pela caixa na tela. */

.vult0-editor:not(.vult0-editor-ativo) > .vult0-editor-caixa {
    display: none;
}

.vult0-editor-ativo fluent-text-area {
    display: none;
}

.vult0-editor-caixa {
    margin-top: 4px;
    border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-rest);
    border-bottom-color: var(--neutral-stroke-strong-rest);
    border-radius: calc(var(--control-corner-radius) * 1px);
    background: var(--neutral-fill-input-rest);
}

.vult0-editor-caixa:focus-within {
    border-bottom-color: var(--accent-fill-rest);
}

.vult0-editor-barra {
    padding: 4px;
    border-bottom: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);
}

/* A prévia ocupa o lugar do editor, com a mesma altura, para a troca de aba
   não fazer a página pular. O conteúdo é o NewsBody, que já vem desenhado. */
.vult0-editor-previa {
    display: none;
    min-height: 320px;
    max-height: 70vh;
    overflow-y: auto;
    padding: 12px 16px;
}

.vult0-editor-previsualizando .vult0-editor-previa {
    display: block;
}

.vult0-editor-previsualizando .vult0-editor-corpo {
    display: none;
}

/* A altura mínima vem de um token que o MarkdownEditor declara no invólucro:
   320px na notícia, e a caixa baixa dos comentários (ADR 0065). O relative é
   para o placeholder abaixo se posicionar sobre a primeira linha. */
.vult0-editor .TinyMDE {
    position: relative;
    min-height: var(--vult0-editor-altura, 320px);
    max-height: 70vh;
    overflow-y: auto;
    padding: 12px 16px;
    outline: none;
    color: var(--neutral-foreground-rest);
    caret-color: var(--neutral-foreground-rest);
    font-family: var(--body-font);
    font-size: var(--type-ramp-base-font-size);
    line-height: var(--type-ramp-base-line-height);
    overflow-wrap: anywhere;
}

/* O TinyMDE só põe a classe e o data-placeholder na caixa vazia; quem desenha
   o texto de exemplo é a folha dele, que não é carregada. Absoluto, sobre a
   linha em branco que ele mantém ali, para não empurrá-la para baixo. */
.vult0-editor .TinyMDE_empty::before {
    content: attr(data-placeholder);
    position: absolute;
    top: 12px;
    left: 16px;
    right: 16px;
    color: var(--neutral-foreground-hint);
    pointer-events: none;
}

.vult0-editor .TMBlankLine {
    height: var(--type-ramp-base-line-height);
}

.vult0-editor :is(.TMH1, .TMSetextH1) {
    font-size: var(--type-ramp-plus-3-font-size);
    line-height: var(--type-ramp-plus-3-line-height);
    font-weight: 500;
}

.vult0-editor :is(.TMH2, .TMSetextH2) {
    font-size: var(--type-ramp-plus-2-font-size);
    line-height: var(--type-ramp-plus-2-line-height);
    font-weight: 500;
}

.vult0-editor .TMH3 {
    font-size: var(--type-ramp-plus-1-font-size);
    line-height: var(--type-ramp-plus-1-line-height);
    font-weight: 500;
}

.vult0-editor :is(.TMH4, .TMH5, .TMH6) {
    font-weight: 500;
}

.vult0-editor .TMStrong {
    font-weight: 600;
}

.vult0-editor .TMEm {
    font-style: italic;
}

.vult0-editor .TMStrikethrough {
    text-decoration: line-through;
}

.vult0-editor :is(.TMMark, .TMMark_TMTask, .TMLinkDestination, .TMImage, .TMHR) {
    color: var(--neutral-foreground-hint);
    text-decoration: none;
}

.vult0-editor :is(.TMCode, .TMMark_TMCode, .TMFencedCodeBacktick, .TMFencedCodeTilde, .TMIndentedCode,
                  .TMCodeFenceBacktickOpen, .TMCodeFenceBacktickClose, .TMCodeFenceTildeOpen,
                  .TMCodeFenceTildeClose, .TMHTML, .TMHTMLBlock) {
    font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
    font-size: var(--type-ramp-minus-1-font-size);
}

.vult0-editor :is(.TMCode, .TMInfoString, .TMLink, .TMLinkLabel, .TMAutolink) {
    color: var(--accent-foreground-rest);
}

/* O bloco de código afunda no layer-2, como o cartão dele na notícia. */
.vult0-editor :is(.TMFencedCodeBacktick, .TMFencedCodeTilde, .TMIndentedCode,
                  .TMCodeFenceBacktickOpen, .TMCodeFenceBacktickClose,
                  .TMCodeFenceTildeOpen, .TMCodeFenceTildeClose) {
    background: var(--neutral-layer-2);
    padding-inline: 12px;
}

.vult0-editor :is(.TMLink, .TMLinkLabel, .TMAutolink) {
    text-decoration: underline;
    font-family: inherit;
}

.vult0-editor .TMBlockquote {
    border-inline-start: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);
    padding-inline-start: 12px;
}

/* A caixa da tarefa é o caractere entre colchetes, com o glifo escondido: o
   texto da linha continua igual ao Markdown, e o desenho vem por cima. */
.vult0-editor .TMCheckbox {
    position: relative;
    color: transparent;
    caret-color: var(--neutral-foreground-rest);
    cursor: pointer;
    font-family: monospace;
}

.vult0-editor .TMCheckbox::before,
.vult0-editor .TMCheckbox_checked::after {
    position: absolute;
    inset: 50% auto auto 50%;
    transform: translate(-50%, -50%);
    pointer-events: none;
}

.vult0-editor .TMCheckbox::before {
    content: "";
    width: 0.9em;
    height: 0.9em;
    box-sizing: border-box;
    border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-strong-rest);
    border-radius: 2px;
}

.vult0-editor .TMCheckbox_checked::before {
    background: var(--accent-fill-rest);
    border-color: var(--accent-fill-rest);
}

.vult0-editor .TMCheckbox_checked::after {
    content: "✓";
    color: var(--foreground-on-accent-rest);
    font-size: 0.75em;
}

/* O editor compacto dos comentários (ADR 0065). O comentário só desenha
   ênfase, tachado e link colado solto; o resto do que a gramática do TinyMDE
   pinta — título, lista, citação, código, [texto](url), imagem, tarefa,
   divisória — sai como texto comum depois de publicado, e é assim que tem
   de aparecer enquanto se digita. Ficam de fora desta lista, e continuam
   pintados, os marcadores de ênfase (`.TMMark` sem sufixo), o escape e o
   `.TMAutolink`, que é o link colado. */
.vult0-editor-compacto :is(.TMH1, .TMH2, .TMH3, .TMH4, .TMH5, .TMH6, .TMSetextH1, .TMSetextH2,
                           .TMBlockquote, .TMCode, .TMHTML, .TMHTMLBlock, .TMIndentedCode,
                           .TMFencedCodeBacktick, .TMFencedCodeTilde, .TMCodeFenceBacktickOpen,
                           .TMCodeFenceBacktickClose, .TMCodeFenceTildeOpen, .TMCodeFenceTildeClose,
                           .TMInfoString, .TMLink, .TMLinkLabel, .TMLinkDestination, .TMLinkTitle,
                           .TMImage, .TMImageDestination, .TMImageTitle, .TMCheckbox, .TMHR,
                           .TMMark_TMH1, .TMMark_TMH2, .TMMark_TMH3, .TMMark_TMH4, .TMMark_TMH5,
                           .TMMark_TMH6, .TMMark_TMSetextH1Marker, .TMMark_TMSetextH2Marker,
                           .TMMark_TMUL, .TMMark_TMOL, .TMMark_TMTask, .TMMark_TMBlockquote,
                           .TMMark_TMHR, .TMMark_TMCode, .TMMark_TMCodeFenceBacktick,
                           .TMMark_TMCodeFenceTilde, .TMMark_TMIndentedCode, .TMMark_TMLink,
                           .TMMark_TMImage, .TMMark_TMLinkReferenceDefinition) {
    font: inherit;
    color: inherit;
    text-decoration: none;
    background: none;
    border: 0;
    padding: 0;
    cursor: text;
}

/* A caixa da tarefa é desenhada por pseudo-elemento, que a regra acima não
   alcança: sem isto o "- [ ]" seguiria virando um quadradinho. */
.vult0-editor-compacto .TMCheckbox::before,
.vult0-editor-compacto .TMCheckbox_checked::after {
    content: none;
}

/* --- links discretos nas listas densas --------------------------------------
   No log de moderação cada linha tinha dois ou três links em accent,
   sublinhados — o olho achava os links, não o que aconteceu. Dentro das
   listas o sublinhado só aparece sob o cursor ou no foco, como já faz o nome
   do torrent na listagem; a cor continua dizendo que é link. Texto corrido
   (notícias, descrições) fica de fora: ali o sublinhado é o que separa o link
   do resto para quem não distingue a cor. */
.vult0-links-discretos a {
    text-decoration: none;
}

.vult0-links-discretos a:hover,
.vult0-links-discretos a:focus-visible {
    text-decoration: underline;
}

/* --- classes de usuário (ADR 0073) ----------------------------------------
   Autorizado pelo dono do projeto: uma cor por insígnia, sem efeito. Não há
   par claro/escuro: o matiz é misturado ao --neutral-foreground-rest do tema,
   que é escuro no claro e claro no escuro, e a mesma regra escurece o nome no
   fundo claro e o clareia no escuro. Uma cor só não passaria nos dois: pela
   luminância, nenhum tom alcança 4,5:1 contra #fbfbfb e contra #272727 ao mesmo tempo. O
   User não tem regra: é a maioria, e fica com a cor do link para as classes
   conquistadas se destacarem. O :hover repete a cor porque o `a:hover` da
   folha do Fluent vence uma classe sozinha. */
.vult0-classe-icone {
    vertical-align: -0.125em;
    margin-right: 0.25em;
}

.vult0-classe-leech, a.vult0-classe-leech:hover { color: color-mix(in srgb, #d13438 65%, var(--neutral-foreground-rest)); }
.vult0-classe-power-user, a.vult0-classe-power-user:hover { color: color-mix(in srgb, #2f8fe0 70%, var(--neutral-foreground-rest)); }
.vult0-classe-elite, a.vult0-classe-elite:hover { color: color-mix(in srgb, #8a5cf5 70%, var(--neutral-foreground-rest)); }
.vult0-classe-torrent-master, a.vult0-classe-torrent-master:hover { color: color-mix(in srgb, #e0a100 55%, var(--neutral-foreground-rest)); }
.vult0-classe-uploader, a.vult0-classe-uploader:hover { color: color-mix(in srgb, #16a34a 70%, var(--neutral-foreground-rest)); }
.vult0-classe-trustee, a.vult0-classe-trustee:hover { color: color-mix(in srgb, #0ea5a5 65%, var(--neutral-foreground-rest)); }
.vult0-classe-moderator, a.vult0-classe-moderator:hover { color: color-mix(in srgb, #e8702a 65%, var(--neutral-foreground-rest)); }
.vult0-classe-administrator, a.vult0-classe-administrator:hover { color: color-mix(in srgb, #e0457b 70%, var(--neutral-foreground-rest)); }
