/* =========================================================================
   Design system do Lnkr. É o único CSS do site e do dashboard — não há
   Bootstrap: o que o template do Blazor trazia foi removido e as classes
   abaixo cobrem o que as páginas usavam (cards, formulários, tabelas,
   alertas, grid).

   Não afeta as páginas públicas dos usuários (/{username}): aquelas são
   documentos HTML crus, montados em PublicPageEndpoints.
   ========================================================================= */

:root {
  --bg: #0f1020;
  --bg-soft: #181a30;
  --card: #1e2038;
  --card-hover: #262946;
  --text: #f5f5fa;
  --muted: #a5a7c0;
  --accent: #7c5cff;
  --accent-2: #ff5c8a;
  /* Roxo clareado: o --accent puro não tem contraste suficiente para texto
     de link sobre o fundo escuro. */
  --accent-soft: #a89bff;
  --ok: #3ddc97;
  --warn: #ffc16b;
  --danger: #ff7a9c;
  --border: rgba(255, 255, 255, 0.08);
  --border-strong: rgba(255, 255, 255, 0.16);
  --radius: 16px;
  --radius-sm: 10px;
  --shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
}

*, *::before, *::after { box-sizing: border-box; }

html, body {
    font-family: "Segoe UI", system-ui, -apple-system, Roboto, Helvetica, Arial, sans-serif;
    margin: 0;
    padding: 0;
    color: var(--text);
    background: var(--bg);
}

/* Links herdam a cor do contexto (topbar, rodapé e hero pintam os seus).
   Onde o link precisa se destacar dentro de texto corrido, use .link. */
a { color: inherit; }

.link { color: var(--accent-soft); text-decoration: underline; text-underline-offset: 2px; }
.link:hover { color: var(--text); }

h1, h2, h3 { line-height: 1.2; }

/* ---------- Botões ---------- */
.btn-lnkr {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .6rem;
  padding: .85rem 1.4rem;
  border-radius: 999px;
  font-weight: 600;
  font-size: 1rem;
  font-family: inherit;
  line-height: 1.2;
  border: none;
  cursor: pointer;
  text-decoration: none;
  transition: transform .12s ease, box-shadow .12s ease, background .12s ease;
}
.btn-lnkr:hover { transform: translateY(-2px); }
.btn-lnkr:disabled, .btn-lnkr[disabled] {
  opacity: .55;
  cursor: not-allowed;
  transform: none;
}
.btn-primary-lnkr {
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: #fff;
  box-shadow: 0 8px 24px rgba(124, 92, 255, .35);
}
.btn-ghost-lnkr {
  background: transparent;
  color: var(--text);
  border: 1px solid var(--border-strong);
}
.btn-ghost-lnkr:hover { background: rgba(255,255,255,.06); }
.btn-sm { padding: .5rem 1rem; font-size: .9rem; }
.btn-lg { padding: 1rem 2rem; font-size: 1.05rem; }
.btn-block { width: 100%; }

/* Foco visível e consistente em tudo que é interativo. */
.btn-lnkr:focus-visible,
.input-lnkr:focus-visible,
.topbar nav a:focus-visible {
  outline: 2px solid var(--accent-soft);
  outline-offset: 2px;
}

/* ---------- Topbar ---------- */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 1.5rem;
  border-bottom: 1px solid var(--border);
  background: rgba(15, 16, 32, .8);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  position: sticky;
  top: 0;
  z-index: 10;
}
.topbar .brand { font-weight: 800; font-size: 1.25rem; letter-spacing: -.02em; text-decoration: none; color: var(--text); }
.topbar .brand span { background: linear-gradient(135deg, var(--accent), var(--accent-2)); -webkit-background-clip: text; background-clip: text; color: transparent; }
.topbar nav { display: flex; gap: 1.25rem; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.topbar nav a { color: var(--muted); font-weight: 500; text-decoration: none; }
.topbar nav a:hover { color: var(--text); }
/* Estado ativo do NavLink, usado pela navegação do dashboard. */
.topbar nav a.active { color: var(--text); }
.topbar nav a.active:not(.btn-lnkr) { box-shadow: inset 0 -2px 0 var(--accent); }

/* "Sair" é um <button> dentro de um <form> (POST), mas precisa parecer link. */
.linkish {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--muted);
  font-weight: 500;
  cursor: pointer;
}
.linkish:hover { color: var(--text); }

@media (max-width: 640px) {
  .topbar { flex-wrap: wrap; padding: .75rem 1rem; }
  .topbar nav { gap: .9rem; font-size: .95rem; width: 100%; justify-content: flex-start; }
}

.container-lnkr { max-width: 960px; margin: 0 auto; padding: 2rem 1.5rem; }
/* O dashboard precisa de mais largura que as páginas de texto: o editor e a
   pré-visualização ficam lado a lado. */
.container-wide { max-width: 1200px; margin: 0 auto; padding: 2rem 1.5rem; }

/* ---------- Landing ---------- */
.hero {
  min-height: 70vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 4rem 1.5rem;
  background: radial-gradient(1200px 600px at 50% -10%, rgba(124,92,255,.25), transparent 60%),
              radial-gradient(900px 500px at 90% 20%, rgba(255,92,138,.18), transparent 60%);
}
.hero h1 {
  font-size: clamp(2.4rem, 6vw, 4rem);
  line-height: 1.05;
  margin: 0 0 1rem;
  font-weight: 800;
  letter-spacing: -.03em;
}
.hero h1 .grad { background: linear-gradient(135deg, var(--accent), var(--accent-2)); -webkit-background-clip: text; background-clip: text; color: transparent; }
.hero p { font-size: 1.2rem; color: var(--muted); max-width: 560px; margin: 0 auto 2rem; }
.hero .cta { display: flex; gap: 1rem; flex-wrap: wrap; justify-content: center; }

.features {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1.25rem;
  max-width: 960px;
  margin: 0 auto;
  padding: 1rem 1.5rem 5rem;
}
.feature {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.5rem;
}
.feature .ico { font-size: 1.8rem; margin-bottom: .6rem; }
.feature h3 { margin: .2rem 0 .4rem; }
.feature p { color: var(--muted); margin: 0; font-size: .95rem; }

/* ---------- Anúncios ---------- */
/* Daqui sai o retângulo; quem põe o anúncio dentro dele é o
   Lnkr/wwwroot/js/ads-banner.js.

   A ALTURA é o que decide o formato: em 90px cabe o banner de 728x90, em 60px o
   de 468x60 — e é o --ad-h abaixo que o script LÊ para escolher qual unidade
   pedir. Mexer nestes números sem mexer em AdUnits.DesktopMinHeight desfaz esse
   acordo, e a faixa passa a reservar um tamanho e exibir outro. */
.ad-slot {
  --ad-h: 90px;
  height: var(--ad-h);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
/* O provedor injeta um iframe dentro do slot; sem isto ele vem com borda. */
.ad-slot iframe { display: block; border: 0; }

/* Landing: no fluxo, logo abaixo do hero, centralizada. */
/* Margem, e não padding: com box-sizing border-box o padding sairia de dentro
   da altura declarada em --ad-h e espremeria o anúncio. */
.ad-slot-landing {
  width: min(100% - 3rem, 744px);
  margin: 0 auto 1rem;
}

/* Painel: flutuando sobre o conteúdo, presa ao rodapé da janela. z-index baixo
   de propósito — o editor em tela cheia (2000) e o aviso de erro (1000) têm de
   continuar passando por cima. */
.ad-slot-sticky {
  position: fixed;
  left: 50%;
  bottom: 12px;
  transform: translateX(-50%);
  width: min(100% - 1rem, 744px);
  border-radius: 12px;
  background: var(--card);
  box-shadow: 0 6px 28px rgba(0, 0, 0, .45);
  overflow: hidden;
  z-index: 40;
}

/* Quanto o conteúdo do painel precisa recuar para a faixa fixa não tapar o seu
   fim: a altura da faixa, mais a folga que ela deixa embaixo, mais um respiro. */
:root { --ad-sticky-space: 114px; }

@media (max-width: 800px) {
  .ad-slot { --ad-h: 60px; }
  .ad-slot-sticky { bottom: 8px; }
  :root { --ad-sticky-space: 80px; }
}

/* ---------- Páginas institucionais (termos, privacidade, 404) ---------- */
.legal h1 { margin-top: 0; }
.legal h2 { margin-top: 2rem; font-size: 1.3rem; }
.legal p, .legal li { color: var(--muted); line-height: 1.6; }
.legal-note { margin-top: 2.5rem; }
.not-found { min-height: 60vh; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 3rem 1.5rem; }

.page-foot { color: var(--muted); border-top: 1px solid var(--border); text-align: center; padding: 1.5rem 1rem; font-size: .875rem; }
.page-foot a { color: var(--muted); text-decoration: none; }
.page-foot a:hover { color: var(--text); }

/* ---------- Consentimento de cookies ---------- */
/* Rodapé fixo, acima de tudo menos do aviso de erro do Blazor. Não escurece a
   página atrás: enquanto não há consentimento também não há anúncio nem
   Analytics, então nada urgente depende de a pessoa responder agora. */
.consent {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 3000;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: center;
  justify-content: center;
  padding: 1rem 1.25rem;
  background: var(--card);
  border-top: 1px solid var(--border);
  box-shadow: 0 -8px 30px rgba(0, 0, 0, .35);
}
.consent-text { max-width: 62ch; }
.consent-text strong { display: block; margin-bottom: .15rem; }
.consent-text p { margin: 0; color: var(--muted); font-size: .8125rem; line-height: 1.45; }
.consent-actions { display: flex; gap: .5rem; flex-shrink: 0; }

/* ---------- Seletor de idioma ---------- */
/* No cabeçalho, ao lado do botão de entrar. A seta é desenhada como imagem de
   fundo em SVG inline: o triângulo nativo do <select> é pintado pelo sistema
   operacional e sai preto sobre o fundo escuro no Windows. */
.lang-select select {
  -webkit-appearance: none;
  appearance: none;
  padding: .35rem 1.9rem .35rem .7rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background-color: transparent;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='%239aa' d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .65rem center;
  background-size: .6rem;
  color: var(--muted);
  font: inherit;
  font-size: .8125rem;
  line-height: 1.4;
  cursor: pointer;
}
.lang-select select:hover { color: var(--text); border-color: var(--muted); }
/* As opções são desenhadas pelo sistema, não pelo nosso CSS: sem cor explícita
   elas herdariam o texto claro sobre o fundo branco do menu nativo. */
.lang-select select option { background: var(--card); color: var(--text); }

/* Sem JavaScript o combo não navega; estes links repõem a saída. */
.lang-fallback { display: flex; gap: .5rem; }
.lang-fallback a { color: var(--muted); text-decoration: underline; font-size: .8125rem; }

/* Rótulo que só o leitor de tela enxerga. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* =========================================================================
   Dashboard — sidebar retrátil
   ========================================================================= */

/* Sem largura máxima: o painel usa a tela inteira. O editor lado a lado e os
   gráficos só ganham com o espaço, e diferente das páginas de texto não há
   linha de leitura para proteger. O respiro lateral encolhe no celular. */
.dash {
  display: flex;
  align-items: flex-start;
  min-height: calc(100vh - 8rem);
  padding: 0 1.5rem;
}

/* O checkbox é só o guardador do estado; quem aparece é o <label>. */
.dash-toggle-state { position: absolute; opacity: 0; pointer-events: none; }

.dash-side {
  flex: 0 0 auto;
  width: 3.75rem;
  border-right: 1px solid var(--border);
  padding: 1.5rem .5rem;
  position: sticky;
  top: 4.5rem;
  transition: width .16s ease;
}
/* :checked = menu aberto. O seletor irmão só alcança daqui pra frente, e é por
   isso que o input vem antes da sidebar no HTML. */
.dash-toggle-state:checked ~ .dash-side { width: 13rem; }

.dash-toggle {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .55rem .7rem;
  margin-bottom: 1rem;
  border-radius: var(--radius-sm);
  color: var(--muted);
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
}
.dash-toggle:hover { background: rgba(255,255,255,.06); color: var(--text); }

/* Ícone "hambúrguer" desenhado em CSS, pra não depender de fonte de ícones. */
.dash-toggle-icon {
  flex: 0 0 auto;
  width: 1.1rem;
  height: 2px;
  background: currentColor;
  position: relative;
}
.dash-toggle-icon::before,
.dash-toggle-icon::after {
  content: "";
  position: absolute;
  left: 0;
  width: 100%;
  height: 2px;
  background: currentColor;
}
.dash-toggle-icon::before { top: -6px; }
.dash-toggle-icon::after { top: 6px; }

.dash-menu { display: flex; flex-direction: column; gap: .25rem; }
.dash-menu a {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .6rem .7rem;
  border-radius: var(--radius-sm);
  color: var(--muted);
  text-decoration: none;
  font-weight: 500;
  white-space: nowrap;
}
.dash-menu a:hover { background: rgba(255,255,255,.06); color: var(--text); }
.dash-menu a.active { background: rgba(124, 92, 255, .16); color: var(--text); }
.dash-menu .ico { flex: 0 0 1.1rem; text-align: center; font-size: .95rem; }

/* Fechado: só os ícones. O rótulo some sem sumir para o leitor de tela — a
   largura zero mantém o texto no documento. */
.dash-toggle-text,
.dash-menu .txt {
  overflow: hidden;
  opacity: 1;
  transition: opacity .12s ease;
}
.dash-toggle-state:not(:checked) ~ .dash-side .dash-toggle-text,
.dash-toggle-state:not(:checked) ~ .dash-side .dash-menu .txt {
  width: 0;
  opacity: 0;
}

/* O recuo embaixo abre espaço para a faixa de anúncio fixa — ver
   --ad-sticky-space na seção de anúncios. */
.dash-main { flex: 1 1 auto; min-width: 0; padding: 1.5rem 0 calc(3rem + var(--ad-sticky-space)) 1.75rem; }

@media (max-width: 720px) {
  .dash { flex-direction: column; }
  .dash-side {
    width: 100%;
    position: static;
    border-right: none;
    border-bottom: 1px solid var(--border);
    padding: .75rem 0;
  }
  .dash-toggle-state:checked ~ .dash-side { width: 100%; }
  .dash-menu { flex-direction: row; flex-wrap: wrap; }
  /* No celular o menu é uma linha de ícones+texto; esconder o texto ali só
     deixaria a navegação adivinhatória. */
  .dash-toggle { display: none; }
  .dash-toggle-state:not(:checked) ~ .dash-side .dash-menu .txt { width: auto; opacity: 1; }
  .dash-main { padding: 1.5rem 0 calc(3rem + var(--ad-sticky-space)); }
}

@media (max-width: 480px) {
  .dash { padding: 0 .875rem; }
}

/* =========================================================================
   Dashboard — conteúdo
   ========================================================================= */

.page-head { margin-bottom: 1.75rem; }
.page-head h1 { margin: 0 0 .35rem; font-size: 1.9rem; letter-spacing: -.02em; }
.page-head p { margin: 0; color: var(--muted); }

/* Card genérico de conteúdo. */
.card-lnkr {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.5rem;
}
.card-lnkr + .card-lnkr { margin-top: 1.25rem; }
.card-lnkr h2 { margin: 0 0 1rem; font-size: 1.05rem; font-weight: 600; }

/* Duas colunas que viram uma só em telas estreitas. */
.split {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 1.5rem;
  align-items: start;
}

.stack { display: flex; flex-direction: column; gap: 1rem; }
.row-wrap { display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: center; }

.muted { color: var(--muted); }
.small-text { font-size: .875rem; }
.center { text-align: center; }

/* ---------- Formulários ---------- */
.field { display: block; margin-bottom: 1rem; }
.field:last-child { margin-bottom: 0; }
.field > .label {
  display: block;
  margin-bottom: .4rem;
  font-size: .875rem;
  font-weight: 600;
  color: var(--muted);
}

.input-lnkr {
  width: 100%;
  padding: .7rem .9rem;
  font: inherit;
  color: var(--text);
  background: var(--bg-soft);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  transition: border-color .12s ease;
}
.input-lnkr::placeholder { color: rgba(165, 167, 192, .6); }
.input-lnkr:focus { outline: none; border-color: var(--accent); }
.input-lnkr:disabled { opacity: .6; cursor: not-allowed; }

textarea.input-lnkr {
  resize: vertical;
  min-height: 8rem;
  font-family: ui-monospace, "Cascadia Code", Consolas, "Courier New", monospace;
  font-size: .875rem;
  line-height: 1.5;
}

.input-lnkr.is-invalid { border-color: var(--danger); }
.input-lnkr.is-valid { border-color: var(--ok); }

/* Campo com prefixo colado (ex.: "lnkr.com.br/" + nome) e botão ao lado. */
.input-group-lnkr { display: flex; flex-wrap: wrap; align-items: stretch; gap: .5rem; }
.input-group-lnkr .prefix {
  display: inline-flex;
  align-items: center;
  padding: 0 .75rem;
  background: var(--bg-soft);
  border: 1px solid var(--border-strong);
  border-right: none;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  color: var(--muted);
  font-size: .9rem;
  white-space: nowrap;
}
.input-group-lnkr .prefix + .input-lnkr {
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  flex: 1 1 8rem;
  min-width: 0;
}
/* Só no prefixo: cancela o gap entre ele e o campo (que devem parecer uma peça
   só) sem cancelar o gap que separa o campo do botão ao lado. */
.input-group-lnkr .prefix { margin-right: -.5rem; }

.field-hint { margin: .4rem 0 0; font-size: .8rem; color: var(--muted); }
.field-hint.error { color: var(--danger); }
.field-hint.ok { color: var(--ok); }

/* ---------- Avisos ---------- */
.alert-lnkr {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: .85rem 1rem;
  margin-bottom: 1.25rem;
  font-size: .925rem;
}
.alert-danger-lnkr { border-color: rgba(255, 122, 156, .45); background: rgba(255, 122, 156, .1); color: var(--danger); }
.alert-warn-lnkr { border-color: rgba(255, 193, 107, .45); background: rgba(255, 193, 107, .1); color: var(--warn); }
.alert-ok-lnkr { border-color: rgba(61, 220, 151, .45); background: rgba(61, 220, 151, .1); color: var(--ok); }

.badge-lnkr {
  display: inline-block;
  padding: .3rem .7rem;
  border-radius: 999px;
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .02em;
  background: rgba(255,255,255,.08);
  color: var(--muted);
}
.badge-ok { background: rgba(61, 220, 151, .15); color: var(--ok); }
.badge-warn { background: rgba(255, 193, 107, .15); color: var(--warn); }

/* ---------- Tabelas ---------- */
/* O wrapper é o que impede a tabela de estourar a largura da página no
   celular — ela rola dentro dele, o body não rola de lado. */
.table-wrap { overflow-x: auto; }
.table-lnkr { width: 100%; border-collapse: collapse; font-size: .925rem; }
.table-lnkr th, .table-lnkr td {
  text-align: left;
  padding: .7rem .75rem;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.table-lnkr th { color: var(--muted); font-size: .8rem; text-transform: uppercase; letter-spacing: .04em; font-weight: 600; }
.table-lnkr tbody tr:hover { background: rgba(255,255,255,.03); }

/* ---------- Números do painel de admin ---------- */
.stat { display: flex; flex-direction: column; gap: .15rem; }
.stat .stat-value { font-size: 1.6rem; font-weight: 800; letter-spacing: -.02em; }
.stat .stat-label { font-size: .8rem; color: var(--muted); }

/* ---------- Seletor de modelos prontos ---------- */
.template-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: .75rem; }
.template-card {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  color: var(--text);
  background: var(--bg-soft);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: .9rem 1rem;
  cursor: pointer;
  transition: border-color .12s ease, background .12s ease;
}
.template-card:hover:not(:disabled) { background: var(--card-hover); border-color: var(--accent); }
.template-card:disabled { opacity: .55; cursor: not-allowed; }
.template-card strong { display: block; margin-bottom: .2rem; }
.template-card span { font-size: .8rem; color: var(--muted); }

/* ---------- Boas-vindas (escolha do endereço) ---------- */
.onboarding { max-width: 34rem; margin: 2rem auto; }
.suggestions { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 1.5rem; }
.btn-ghost-lnkr.active { border-color: var(--accent); background: rgba(124, 92, 255, .12); }

/* ---------- Pré-visualização da página do usuário ---------- */
/* Fundo branco explícito: o conteúdo dentro do iframe é a página pública do
   usuário, que não herda (nem deve herdar) o tema escuro do painel. */
.preview-frame {
  /* flex-grow para acompanhar a altura do painel de código ao lado, que é
     quem manda na altura da linha. */
  flex: 1 1 auto;
  width: 100%;
  min-height: 24rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: #fff;
}

/* =========================================================================
   Editor: código e pré-visualização lado a lado, com modo tela cheia
   ========================================================================= */

.editor { display: flex; flex-direction: column; gap: 1rem; }

.editor-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .75rem;
}
.editor-bar .spacer { flex: 1 1 auto; }

/* As duas colunas. min-height:0 nos filhos é o que permite o textarea encolher
   dentro do grid em vez de esticar a página. */
.editor-panes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  align-items: stretch;
  min-height: 32rem;
}
.editor-pane { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
.editor-pane > .card-lnkr { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }

/* Empilhado: uma coluna só. */
.editor-panes.stacked { grid-template-columns: 1fr; }

/* Tela cheia: sai do fluxo e cobre a janela, mantendo as duas colunas. */
.editor.fullscreen {
  position: fixed;
  inset: 0;
  z-index: 2000;
  background: var(--bg);
  padding: 1rem;
  margin: 0;
  overflow: auto;
}
.editor.fullscreen .editor-panes { min-height: calc(100vh - 7rem); }

@media (max-width: 860px) {
  .editor-panes { grid-template-columns: 1fr; }
}

/* =========================================================================
   Editor de código — aparência do VS Code (tema Dark+)
   ========================================================================= */

:root {
  --code-bg: #1e1e1e;
  --code-fg: #d4d4d4;
  --code-gutter: #858585;
  --code-caret: #aeafad;
  --code-selection: #264f78;
  --code-border: #2d2d30;

  /* Uma métrica só para as três camadas. Qualquer divergência entre o texto
     de baixo e o de cima aparece como sombra deslocada nas letras — por isso
     fonte, tamanho, entrelinha e recuo vêm daqui, e não de cada regra. */
  --code-font: ui-monospace, "Cascadia Code", "Consolas", "Courier New", monospace;
  --code-size: 13px;
  --code-line: 1.55;
  --code-pad-y: .9rem;
  --code-pad-x: .9rem;
}

.code-editor {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  background: var(--code-bg);
  border: 1px solid var(--code-border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
/* O atributo hidden precisa vencer o display:flex acima quando o editor está
   na aba que não está à mostra. */
.code-editor[hidden] { display: none; }

.code-gutter {
  flex: 0 0 auto;
  width: 3.25rem;
  padding: var(--code-pad-y) .6rem;
  overflow: hidden;
  text-align: right;
  color: var(--code-gutter);
  background: var(--code-bg);
  border-right: 1px solid var(--code-border);
  font-family: var(--code-font);
  font-size: var(--code-size);
  line-height: var(--code-line);
  white-space: pre;
  -webkit-user-select: none;
  user-select: none;
}

.code-surface { position: relative; flex: 1 1 auto; min-width: 0; }

/* As duas camadas ocupam exatamente o mesmo retângulo. */
.code-highlight,
.code-input {
  margin: 0;
  border: 0;
  padding: var(--code-pad-y) var(--code-pad-x);
  font-family: var(--code-font);
  font-size: var(--code-size);
  line-height: var(--code-line);
  letter-spacing: normal;
  tab-size: 2;
  /* Sem quebra automática: é assim no VS Code, e é o que garante que as duas
     camadas quebrem as linhas nos mesmos lugares — ou seja, nunca. */
  white-space: pre;
  word-break: normal;
}

.code-highlight {
  position: absolute;
  inset: 0;
  overflow: hidden;
  color: var(--code-fg);
  background: var(--code-bg);
  pointer-events: none;
}
.code-highlight code { font: inherit; }

.code-input {
  position: relative;
  width: 100%;
  height: 100%;
  display: block;
  overflow: auto;
  resize: none;
  background: transparent;
  /* O texto real fica invisível: quem se vê é a camada colorida atrás. O
     cursor e a seleção continuam sendo os nativos do textarea. */
  color: transparent;
  caret-color: var(--code-caret);
}
.code-input::selection { background: var(--code-selection); }
.code-input:focus { outline: none; }
.code-editor:focus-within { border-color: #007fd4; }

/* Paleta Dark+ */
.tok-plain    { color: #d4d4d4; }
.tok-comment  { color: #6a9955; }
.tok-tag      { color: #569cd6; }
.tok-attr     { color: #9cdcfe; }
.tok-string   { color: #ce9178; }
.tok-punct    { color: #808080; }
.tok-selector { color: #d7ba7d; }
.tok-atrule   { color: #c586c0; }
.tok-prop     { color: #9cdcfe; }
.tok-value    { color: #ce9178; }
.tok-number   { color: #b5cea8; }

/* =========================================================================
   Gráficos da visão geral
   ========================================================================= */

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1rem;
  margin-bottom: 1.25rem;
}
.stat-tile {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.1rem 1.25rem;
}
.stat-tile .stat-label {
  display: block;
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--muted);
  margin-bottom: .35rem;
}
.stat-tile .stat-value { font-size: 1.9rem; font-weight: 800; letter-spacing: -.02em; line-height: 1.1; }
.stat-tile .stat-note { font-size: .8rem; color: var(--muted); }
.stat-tile .stat-note.up { color: var(--ok); }
.stat-tile .stat-note.down { color: var(--danger); }

/* Seletor de período (dia / mês / ano). */
.range-tabs { display: flex; gap: .4rem; flex-wrap: wrap; }
.range-tabs button {
  font: inherit;
  font-size: .85rem;
  font-weight: 600;
  padding: .4rem .9rem;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.range-tabs button:hover { color: var(--text); background: rgba(255,255,255,.06); }
.range-tabs button.active { background: rgba(124, 92, 255, .16); border-color: var(--accent); color: var(--text); }

/* Barras em CSS puro: uma coluna de grid por ponto, altura em %. Um gráfico
   assim não precisa de biblioteca nem de medir o container em JavaScript. */
.bars {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  align-items: end;
  gap: 2px;
  height: 13rem;
  padding-top: .5rem;
  border-bottom: 1px solid var(--border);
}
.bars .bar {
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  height: 100%;
  min-width: 0;
}
.bars .bar .fill {
  width: 100%;
  max-width: 2.2rem;
  background: var(--accent);
  /* Ponta arredondada só em cima: embaixo a barra encosta na linha de base. */
  border-radius: 4px 4px 0 0;
  transition: background .12s ease;
  min-height: 2px;
}
.bars .bar:hover .fill { background: var(--accent-soft); }
/* Dia sem visita continua ocupando a coluna: some a barra, não o eixo. */
.bars .bar.empty .fill { background: rgba(255,255,255,.07); }

.bars-axis {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 2px;
  margin-top: .5rem;
  font-size: .7rem;
  color: var(--muted);
}
.bars-axis span {
  text-align: center;
  overflow: hidden;
  white-space: nowrap;
}

/* Ranking de origens: barra de magnitude atrás do texto. */
.source-list { display: flex; flex-direction: column; gap: .5rem; }
.source-row {
  position: relative;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: .55rem .75rem;
  border-radius: var(--radius-sm);
  background: var(--bg-soft);
  overflow: hidden;
}
.source-row .meter {
  position: absolute;
  inset: 0 auto 0 0;
  background: rgba(124, 92, 255, .22);
}
.source-row .name,
.source-row .count { position: relative; }
.source-row .count { color: var(--muted); font-variant-numeric: tabular-nums; }

.empty-state {
  text-align: center;
  padding: 3rem 1.5rem;
  color: var(--muted);
}
.empty-state h2 { color: var(--text); margin-bottom: .5rem; font-size: 1.1rem; }

/* =========================================================================
   Banner de erro do Blazor
   Global (e não em CSS escopado de um layout): o mesmo elemento aparece em
   todos os layouts. Escopado num só, os demais o exibiriam sempre — sem o
   display:none, o aviso de erro fica permanentemente visível.
   ========================================================================= */
#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    color: #212529;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

/* ---------- Validação de formulários do Blazor ---------- */
.valid.modified:not([type=checkbox]) { outline: 1px solid var(--ok); }
.invalid { outline: 1px solid var(--danger); }
.validation-message { color: var(--danger); font-size: .8rem; }

h1:focus { outline: none; }

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

.blazor-error-boundary::after { content: "Ocorreu um erro." }
