/* ============================================================================
   tokens.css — camada de tokens + primitivas do HUB DE FIDELIDADE
   ----------------------------------------------------------------------------
   ORDEM DE CARGA (obrigatória em toda página do cliente):
       <link rel="stylesheet" href="/css/style.css">
       <link rel="stylesheet" href="/css/tokens.css">   <-- SEMPRE depois
   Carregado depois, este arquivo vence os conflitos de :root. Ele é ADITIVO:
   não redefine nenhum token existente do style.css (--bg, --panel, --radius,
   --blue, --gold, --text, --muted seguem intactos). Só acrescenta o que a obra
   de fidelidade precisa e o design system atual não tem.

   CSP self: fontes já são self-hosted pelo style.css. Nenhum @font-face novo,
   nenhum asset externo, nenhuma url() remota aqui.

   SISTEMA DE FORMA (uma regra, seguida em tudo):
       pílula (--r-pill) = chips, badges, botões pequenos
       --r-md            = tiles, botões, campos
       --r-lg            = cartões
   SISTEMA DE MOVIMENTO:
       ≤ --dur-3 para feedback (o usuário vê muitas vezes por dia)
       --dur-4/--dur-5 só para o momento autoral: celebração, contador, medidor
       Toda animação nova tem contrapartida em prefers-reduced-motion no fim
       deste arquivo (não confiamos só no bloco global do style.css).

   CONTRASTE: todo par texto/fundo daqui foi medido. Valores no comentário de
   cada bloco. Piso AA (4.5:1) para texto normal; nada abaixo disso foi usado.
   ATENÇÃO: --blue (#2F6BFF) dá 3.92:1 sobre --panel. É token de PREENCHIMENTO
   e de texto grande, nunca de texto corrido sobre painel. Para texto use
   --blue-light (6.66:1) ou --text.
   ========================================================================== */

:root {
  /* ---------- escala de espaçamento (base 4) ---------- */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;
  --sp-8: 64px;

  /* ---------- escala de raio ---------- */
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 18px;
  --r-pill: 999px;

  /* ---------- elevação (offset + blur suave; halo sem offset é decoração) --- */
  --sh-1: 0 1px 2px rgba(2, 5, 15, 0.50), 0 2px 8px rgba(2, 5, 15, 0.28);
  --sh-2: 0 2px 6px rgba(2, 5, 15, 0.50), 0 10px 24px rgba(2, 5, 15, 0.36);
  --sh-3: 0 4px 12px rgba(2, 5, 15, 0.55), 0 22px 48px rgba(2, 5, 15, 0.44);

  /* ---------- escala tipográfica ---------- */
  --fs-0: 11px;   /* rótulo micro, all-caps */
  --fs-1: 12px;   /* legenda */
  --fs-2: 13px;   /* apoio, nav */
  --fs-3: 15px;   /* corpo compacto */
  --fs-4: 16px;   /* corpo */
  --fs-5: 20px;   /* título de cartão */
  --fs-6: 26px;   /* título de seção */
  --fs-7: 34px;   /* número de destaque */
  --fs-8: 44px;   /* número herói (prêmio, giro) */

  --lh-tight: 1.15;
  --lh-snug: 1.35;
  --lh-body: 1.55;
  --track-caps: 1.6px;   /* all-caps precisa de tracking positivo */
  --track-display: 0.5px;

  /* ---------- movimento ---------- */
  --dur-1: 120ms;   /* pressão de botão */
  --dur-2: 180ms;   /* chip, tab, hover */
  --dur-3: 260ms;   /* cartão, toast */
  --dur-4: 420ms;   /* medidor preenchendo */
  --dur-5: 900ms;   /* celebração, contador */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --ease-pop: cubic-bezier(0.16, 1, 0.3, 1);   /* expo out; o "pop" vem do keyframe, nao de bounce no easing */

  /* ---------- superfícies do hub ---------- */
  /* --surface = painel levemente elevado; medido #161e39 */
  --surface: rgba(255, 255, 255, 0.03);
  --surface-2: rgba(255, 255, 255, 0.06);
  --surface-sunken: #060a18;              /* trilho/recesso, mais escuro que o cartão */
  --hairline: rgba(255, 255, 255, 0.07);
  --border-soft: rgba(47, 107, 255, 0.22);

  /* texto secundário/terciário (não sobrescrevem --muted do style.css) */
  --text-2: #a7b6cc;   /* 9.52:1 sobre --bg · 8.57:1 sobre --panel · 7.98:1 sobre --surface */
  --text-3: #8595ad;   /* apoio discreto, ainda AA: 6.44:1 sobre --bg · 5.79:1 sobre --panel */

  /* ---------- níveis VIP (bronze fosco → prata → dourado quente) ---------- */
  /* nomes default da spec: 1 Reserva · 2 Titular · 3 Craque */
  --tier1: #cd8d4e;                 /* bronze fosco */
  --tier1-ink: #e0ac7a;             /* 7.10:1 sobre o tinte do próprio tier */
  --tier1-grad: linear-gradient(135deg, #8d5f34, #cd8d4e 46%, #e6b98c);
  --tier2: #c0c8d8;                 /* prata */
  --tier2-ink: #dfe5f0;             /* 10.30:1 sobre o tinte */
  --tier2-grad: linear-gradient(135deg, #78829a, #c0c8d8 46%, #eef2f8);
  --tier3: #ffc400;                 /* dourado quente */
  --tier3-ink: #ffc400;             /* 8.36:1 sobre o tinte */
  --tier3-grad: linear-gradient(135deg, #b8860b, #ffc400 42%, #ffe89a);
  --on-tier: #070B1A;               /* 7.01 / 11.66 / 12.27 sobre os 3 metais */

  /* ---------- sequência (chama) ---------- */
  --streak: #ff9d3c;
  --streak-ink: #ffab52;            /* 7.41:1 sobre o tinte de chama */
  --streak-tint: rgba(255, 157, 60, 0.14);
  --streak-grad: linear-gradient(135deg, #ff6b2c, #ff9d3c 55%, #ffcf7a);

  /* ---------- escudo de sequência ---------- */
  --shield: #7cd4fd;                /* 11.84:1 sobre --bg */
  --shield-ink: #7cd4fd;            /* 8.23:1 sobre o tinte de escudo */
  --shield-tint: rgba(124, 212, 253, 0.12);

  /* ---------- giro disponível ---------- */
  --spin: #ffd76a;                  /* 14.16:1 sobre --bg */
  --spin-ink: #ffd76a;              /* 8.72:1 sobre o tinte de giro */
  --spin-tint: rgba(255, 196, 0, 0.18);
  --spin-grad: linear-gradient(135deg, #F5C542, #FFD76A, #F5C542);

  /* ---------- near-miss (sóbrio; JAMAIS o vermelho de erro) ---------- */
  /* "Quase! Tente semana que vem" não é falha do usuário: aço calmo, não alarme */
  --nearmiss: #a9b6d4;
  --nearmiss-ink: #b3bfda;          /* 7.98:1 sobre o tinte */
  --nearmiss-tint: rgba(169, 182, 212, 0.10);

  /* ---------- bloqueio amigável ---------- */
  --lock-tint: rgba(47, 107, 255, 0.08);
  --lock-ink: #a7b6cc;              /* 7.90:1 sobre o tinte de bloqueio */

  /* ---------- camadas ---------- */
  --z-base: 1;
  --z-sticky: 10;
  --z-overlay: 20;
  --z-toast: 30;
}

/* ============================================================================
   NAV DE 4 ABAS — Palpites · Roleta · Ranking · Regulamento
   ----------------------------------------------------------------------------
   DECISÃO 390px: as abas viram GRID de colunas iguais com ícone EM CIMA do
   rótulo. Grid resolve o problema por construção, não por gambiarra:
     grid-auto-flow: column + grid-auto-columns: minmax(0, 1fr)
   distribui N abas (3 sem roleta, 4 com) em colunas idênticas que NUNCA
   estouram, porque minmax(0,1fr) autoriza a coluna a ficar menor que o
   conteúdo em vez de empurrar a linha. O rótulo abaixo do ícone libera a
   largura que a versão inline gastava com o gap horizontal.
   Conta em 390px: 390 - 32 (padding do .wrap) - 2 (borda) - 12 (padding da
   pílula) - 12 (3 gaps de --sp-1) = 332px / 4 = 83px por aba (medido em
   Playwright: 83x52 nas 4). "Regulamento" a 11px ocupa ~58px: sobra folga
   real, não aperto. Com 3 abas (roleta OFF) cada uma fica com 112px.
   Alvo de toque: 52px de altura mínima (piso de 44px com margem).
   Mantivemos a pílula no topo (e não uma bottom-nav fixa) porque a bottom-nav
   colidiria com o rodapé/prompt de PWA já existentes e mudaria a memória
   muscular de quem já usa o app.
   ========================================================================== */

.tabs {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  align-items: stretch;
  gap: var(--sp-1);
}

.tabs a {
  flex: none;
  flex-direction: column;
  gap: var(--sp-1);
  min-width: 0;
  min-height: 52px;
  padding: var(--sp-2) var(--sp-1);
  border-radius: var(--r-md);
  font-size: var(--fs-0);
  font-weight: 700;
  letter-spacing: 0.2px;
  line-height: var(--lh-tight);
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: background var(--dur-2) var(--ease-out), color var(--dur-2) var(--ease-out);
}

.tabs svg {
  width: 18px;
  height: 18px;
}

/* ARMADILHA (vale para a obra inteira): o atributo [hidden] só vira display:none
   pela folha do navegador — QUALQUER regra de autor com `display` o anula.
   O style.css faz isso em `.tabs a` (display:flex) e em `.streak-chip`
   (display:inline-flex), então hoje o #streakChip com [hidden] renderiza uma
   pílula dourada vazia no topo de /palpites. Esta linha conserta a classe
   inteira de bug de uma vez, para todas as páginas que carregam tokens.css. */
[hidden] { display: none !important; }

/* aba corrente: marcada por aria-current, não só por classe */
.tabs a[aria-current="page"],
.tabs a.active {
  background: rgba(47, 107, 255, 0.16);
  color: var(--blue-light);
  box-shadow: inset 0 0 0 1px var(--border-soft);
}

/* selo de novidade na aba Roleta (o builder do hub liga com .has-dot) */
.tabs a.has-dot { position: relative; }
.tabs a.has-dot::after {
  content: "";
  position: absolute;
  top: 6px;
  right: calc(50% - 20px);
  width: 6px;
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--spin);
  box-shadow: 0 0 0 2px var(--panel);
}

@media (hover: hover) and (pointer: fine) {
  .tabs a:hover:not([aria-current="page"]) { background: rgba(255, 255, 255, 0.04); }
}

@media (max-width: 360px) {
  .tabs { gap: 2px; }
  .tabs a { font-size: 10px; padding: var(--sp-2) 0; }
  .tabs svg { width: 17px; height: 17px; }
}

/* ============================================================================
   PRIMITIVAS
   ========================================================================== */

/* ---------- .hub-card — contêiner base do hub ----------------------------- */
/* texto sobre a superfície #161e39: --text 14.62:1 · --text-2 7.98:1          */
.hub-card {
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background:
    linear-gradient(180deg, var(--surface-2), transparent 62%),
    var(--panel);
  box-shadow: var(--sh-1);
  padding: var(--sp-4);
  overflow: hidden;
}
.hub-card > * + * { margin-top: var(--sp-3); }
.hub-card__title {
  font-family: var(--font-display);
  font-size: var(--fs-5);
  line-height: var(--lh-tight);
  letter-spacing: var(--track-display);
  color: var(--text);
}
.hub-card__note {
  font-size: var(--fs-2);
  line-height: var(--lh-snug);
  color: var(--text-2);
}
/* variantes de acento: 1px de borda tingida, sem faixa lateral grossa */
.hub-card--gold { border-color: rgba(255, 196, 0, 0.34); }
.hub-card--gold::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(120% 80% at 50% -30%, rgba(255, 196, 0, 0.10), transparent 68%);
}
.hub-card--flat { background: var(--panel); box-shadow: none; }

/* ---------- .stat-tile — número + rótulo em grade ------------------------- */
.stat-tile {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  min-width: 0;
  padding: var(--sp-3);
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  background: var(--surface);
}
.stat-tile__value {
  font-family: var(--font-display);
  font-size: var(--fs-6);
  line-height: var(--lh-tight);
  letter-spacing: var(--track-display);
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
/* rótulo secundário é tingido a partir do matiz da própria superfície, nunca
   cinza: --text-3 reprova AA (3.62/4.20/4.11) sobre os tintes de ouro, chama e
   escudo. Os valores abaixo foram medidos sobre a superfície final composta. */
.stat-tile__label {
  font-size: var(--fs-0);
  font-weight: 700;
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  color: var(--text-2);            /* 7.35:1 sobre a superfície base do tile */
}
.stat-tile--gold  { border-color: rgba(255, 196, 0, 0.30);  background: var(--spin-tint); }
.stat-tile--gold  .stat-tile__value { color: var(--spin-ink); }
.stat-tile--gold  .stat-tile__label { color: #d8c79a; }   /* 6.59:1 */
.stat-tile--flame { border-color: rgba(255, 157, 60, 0.30); background: var(--streak-tint); }
.stat-tile--flame .stat-tile__value { color: var(--streak-ink); }
.stat-tile--flame .stat-tile__label { color: #dcc3b4; }   /* 7.61:1 */
.stat-tile--shield{ border-color: rgba(124, 212, 253, 0.28); background: var(--shield-tint); }
.stat-tile--shield .stat-tile__value { color: var(--shield-ink); }
.stat-tile--shield .stat-tile__label { color: #b6cadf; }  /* 7.45:1 */

/* giro disponível: o único elemento da tela que chama atenção sozinho.
   3 pulsos e para — laço infinito vira ruído. */
.stat-tile--live { animation: hubHalo 2400ms var(--ease-in-out) 3; }
@keyframes hubHalo {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 196, 0, 0.00); }
  45%      { box-shadow: 0 0 0 4px rgba(255, 196, 0, 0.14); }
}

/* ---------- .hub-stat-grid — grade de tiles do hub ------------------------ */
/* DÍVIDA C8b QUITADA (docs/REGRESSAO-HUB.md): esta regra se chamava
   `.stat-grid` e SEQUESTRAVA uma classe que já era do painel antigo (definida
   em style.css desde a era semanal). Como tokens.css carrega depois, ela vencia
   e espremia o grid de Engajamento do admin em 390px — que precisou de um
   neutralizador escopado em admin-hub.css pra voltar ao normal.
   O nome agora é próprio. Ninguém precisa desfazer nada de ninguém.
   (O neutralizador `#panelView .stat-grid` em admin-hub.css virou código morto:
   ele só restaura o que style.css já diz. Arquivo de outro builder: reportado,
   não editado.) */
.hub-stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  gap: var(--sp-2);
}

/* ---------- .badge-tier — selo de nível VIP ------------------------------- */
/* data-tier="1|2|3". Metal no anel e no texto; miolo é tinte do metal.       */
.badge-tier {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 5px 12px 5px 8px;
  border-radius: var(--r-pill);
  border: 1px solid currentColor;
  font-family: var(--font-display);
  font-size: var(--fs-1);
  letter-spacing: var(--track-display);
  line-height: 1.4;
  white-space: nowrap;
  color: var(--tier1-ink);
  background: rgba(205, 141, 78, 0.14);
}
.badge-tier__pip {
  width: 14px;
  height: 14px;
  flex: none;
  border-radius: var(--r-pill);
  background: var(--tier1-grad);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.42);
}
.badge-tier[data-tier="2"] { color: var(--tier2-ink); background: rgba(192, 200, 216, 0.14); }
.badge-tier[data-tier="2"] .badge-tier__pip { background: var(--tier2-grad); }
.badge-tier[data-tier="3"] { color: var(--tier3-ink); background: rgba(255, 196, 0, 0.14); }
.badge-tier[data-tier="3"] .badge-tier__pip { background: var(--tier3-grad); }
.badge-tier--lg { font-size: var(--fs-3); padding: 7px 16px 7px 10px; }
.badge-tier--lg .badge-tier__pip { width: 18px; height: 18px; }

/* ---------- .chip-streak — sequência semanal ------------------------------ */
.chip-streak {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px;
  border-radius: var(--r-pill);
  border: 1px solid rgba(255, 157, 60, 0.30);
  background: var(--streak-tint);
  color: var(--streak-ink);
  font-size: var(--fs-1);
  font-weight: 700;
  line-height: 1.4;
  white-space: nowrap;
}
.chip-streak svg { width: 14px; height: 14px; flex: none; }
.chip-streak--shield {
  border-color: rgba(124, 212, 253, 0.28);
  background: var(--shield-tint);
  color: var(--shield-ink);
}
.chip-streak--quiet {
  border-color: var(--hairline);
  background: var(--surface);
  color: var(--text-3);
}
/* pop único quando a sequência acabou de subir; nada de laço perpétuo */
.chip-streak.is-new { animation: hubPop var(--dur-3) var(--ease-pop); }
@keyframes hubPop {
  from { transform: scale(0.94); }
  60%  { transform: scale(1.05); }
  to   { transform: scale(1); }
}

/* ---------- .meter — barra com preenchimento animado por --fill ----------- */
/* Uso:  <div class="meter" style="--fill:.42" role="progressbar"
            aria-valuenow="42" aria-valuemin="0" aria-valuemax="100">
            <div class="meter__fill"></div></div>
   --fill é fração 0..1. O preenchimento é revelado por clip-path (não por
   width): não dispara layout e não deforma o gradiente.                       */
.meter {
  position: relative;
  height: 10px;
  border-radius: var(--r-pill);
  background: var(--surface-sunken);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.55);
  overflow: hidden;
}
.meter__fill {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--spin-grad);
  clip-path: inset(0 calc((1 - var(--fill, 0)) * 100%) 0 0 round var(--r-pill));
  transition: clip-path var(--dur-4) var(--ease-out);
}
.meter--slim { height: 6px; }
.meter--tall { height: 14px; }
.meter--tier1 .meter__fill { background: var(--tier1-grad); }
.meter--tier2 .meter__fill { background: var(--tier2-grad); }
.meter--flame .meter__fill { background: var(--streak-grad); }
.meter--blue  .meter__fill { background: var(--blue-grad); }
.meter__caption {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-top: 6px;
  font-size: var(--fs-1);
  color: var(--text-2);
}
.meter__caption b { color: var(--text); font-weight: 700; }

/* ---------- .toast — feedback flutuante ----------------------------------- */
/* Empilhável. Transição (não keyframe) para poder ser interrompida e
   retargetada quando chegam vários seguidos. Saída mais rápida que a entrada. */
.toast-host {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4) calc(var(--sp-4) + env(safe-area-inset-bottom, 0px));
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  width: 100%;
  max-width: 420px;
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--panel-2);
  box-shadow: var(--sh-3);
  color: var(--text);              /* 14.28:1 sobre --panel-2 */
  font-size: var(--fs-3);
  line-height: var(--lh-snug);
  opacity: 1;
  transform: translateY(0) scale(1);
  transition:
    opacity var(--dur-3) var(--ease-out),
    transform var(--dur-3) var(--ease-out);
}
.toast[data-state="enter"] { opacity: 0; transform: translateY(100%) scale(0.96); }
.toast[data-state="exit"]  { opacity: 0; transform: translateY(40%) scale(0.97); transition-duration: var(--dur-2); }
.toast__msg {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}
.toast__dot {
  flex: none;
  width: 8px;
  height: 8px;
  margin-top: 7px;
  border-radius: var(--r-pill);
  background: var(--blue-light);
}
.toast--ok    { border-color: rgba(0, 230, 118, 0.30); }
.toast--ok    .toast__dot { background: var(--green); }
.toast--prize { border-color: rgba(255, 196, 0, 0.34); }
.toast--prize .toast__dot { background: var(--spin); }
.toast--warn  { border-color: rgba(169, 182, 212, 0.28); }
.toast--warn  .toast__dot { background: var(--nearmiss); }
.toast--err   { border-color: rgba(255, 84, 112, 0.34); }
.toast--err   .toast__dot { background: var(--red); }

/* ---------- .celebrate — glow + confete em CSS puro ----------------------- */
/* O elemento que celebra recebe .celebrate; o JS adiciona .is-celebrating e
   injeta N spans .celebrate__bit com --dx/--dy/--rot/--delay. Sem som,
   sem imagem, sem biblioteca. Contido no próprio cartão (overflow: hidden).  */
.celebrate { position: relative; }
.celebrate__bloom {
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: inherit;
  opacity: 0;
  background: radial-gradient(60% 60% at 50% 46%, rgba(255, 196, 0, 0.34), transparent 70%);
}
.celebrate.is-celebrating .celebrate__bloom {
  animation: hubBloom var(--dur-5) var(--ease-out) forwards;
}
@keyframes hubBloom {
  0%   { opacity: 0; transform: scale(0.9); }
  22%  { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.06); }
}
.celebrate__bit {
  position: absolute;
  top: 46%;
  left: 50%;
  width: 7px;
  height: 10px;
  border-radius: 2px;
  pointer-events: none;
  opacity: 0;
  background: var(--bit-color, var(--spin));
  animation: hubConfetti 1100ms var(--ease-out) var(--delay, 0ms) forwards;
}
@keyframes hubConfetti {
  0%   { opacity: 0; transform: translate3d(-50%, -50%, 0) scale(0.6) rotate(0deg); }
  12%  { opacity: 1; }
  100% { opacity: 0; transform: translate3d(calc(-50% + var(--dx, 0px)), calc(-50% + var(--dy, 0px)), 0) scale(1) rotate(var(--rot, 180deg)); }
}
/* fallback estático: destaque sem movimento (reduced-motion e sem-JS) */
.celebrate.is-celebrating-static {
  box-shadow: inset 0 0 0 1px rgba(255, 196, 0, 0.55), var(--sh-2);
}

/* ---------- .skeleton — carregamento com a forma do resultado ------------- */
.skeleton {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-md);
  background: var(--panel-2);
}
.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.06) 45%, transparent);
  transform: translateX(-100%);
  animation: hubShimmer 1400ms linear infinite;
}
@keyframes hubShimmer {
  to { transform: translateX(100%); }
}
.skeleton--text  { height: 12px; border-radius: var(--r-sm); }
.skeleton--title { height: 22px; width: 60%; border-radius: var(--r-sm); }
.skeleton--tile  { height: 76px; }
.skeleton--card  { height: 148px; border-radius: var(--r-lg); }
.skeleton + .skeleton { margin-top: var(--sp-2); }

/* ---------- .empty-state — nunca tela morta ------------------------------- */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--sp-3);
  padding: var(--sp-6) var(--sp-4);
  border: 1px dashed var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
}
.empty-state__icon {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: var(--r-pill);
  background: var(--lock-tint);
  color: var(--blue-light);
}
.empty-state__icon svg { width: 24px; height: 24px; }
.empty-state__title {
  font-family: var(--font-display);
  font-size: var(--fs-5);
  line-height: var(--lh-tight);
  letter-spacing: var(--track-display);
  color: var(--text);
}
.empty-state__body {
  max-width: 34ch;
  font-size: var(--fs-3);
  line-height: var(--lh-body);
  color: var(--text-2);
}

/* ---------- .lock-card — bloqueio AMIGÁVEL, nunca punitivo ---------------- */
/* Sem vermelho, sem cadeado raivoso, sem "acesso negado". Azul calmo, o
   caminho de saída em destaque dourado e o "fale com a gente" logo abaixo.   */
.lock-card {
  border: 1px solid var(--border-soft);
  border-radius: var(--r-lg);
  background:
    radial-gradient(120% 90% at 50% -20%, rgba(47, 107, 255, 0.12), transparent 70%),
    var(--panel);
  box-shadow: var(--sh-1);
  padding: var(--sp-5) var(--sp-4);
  text-align: center;
}
.lock-card__icon {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  margin: 0 auto var(--sp-3);
  border-radius: var(--r-pill);
  background: var(--lock-tint);
  color: var(--blue-light);
  box-shadow: inset 0 0 0 1px var(--border-soft);
}
.lock-card__icon svg { width: 24px; height: 24px; }
.lock-card__title {
  font-family: var(--font-display);
  font-size: var(--fs-5);
  line-height: var(--lh-tight);
  letter-spacing: var(--track-display);
  color: var(--text);
}
.lock-card__body {
  margin: var(--sp-2) auto 0;
  max-width: 36ch;
  font-size: var(--fs-3);
  line-height: var(--lh-body);
  color: var(--lock-ink);          /* 7.90:1 sobre o tinte de bloqueio */
}
.lock-card__actions {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}
.lock-card__hint {
  margin-top: var(--sp-3);
  font-size: var(--fs-1);
  color: var(--text-3);
}

/* ---------- botões do hub ------------------------------------------------- */
/* --on-tier (#070B1A) sobre dourado = 12.27:1                                */
.hub-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 48px;
  padding: 0 var(--sp-5);
  border: 0;
  border-radius: var(--r-md);
  background: var(--spin-grad);
  color: var(--on-tier);
  font-family: var(--font-display);
  font-size: var(--fs-3);
  letter-spacing: var(--track-display);
  cursor: pointer;
  box-shadow: var(--sh-1);
  transition: transform var(--dur-1) var(--ease-out), filter var(--dur-2) var(--ease-out);
}
.hub-btn:active { transform: scale(0.97); }
.hub-btn[disabled] { opacity: 0.5; cursor: not-allowed; }
.hub-btn--ghost {
  background: none;
  color: var(--text-2);
  box-shadow: inset 0 0 0 1px var(--border);
  font-family: var(--font-body);
  font-weight: 700;
}
@media (hover: hover) and (pointer: fine) {
  .hub-btn:hover:not([disabled]) { filter: brightness(1.06); }
  .hub-btn--ghost:hover:not([disabled]) { color: var(--text); }
}

/* ---------- ritmo vertical das seções do hub ------------------------------ */
.hub-section:not([hidden]) + .hub-section:not([hidden]) { margin-top: var(--sp-4); }
.hub-section:empty { display: none; }

/* ---------- utilitários mínimos ------------------------------------------ */
.hub-row { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.hub-row--between { justify-content: space-between; }
.hub-num { font-variant-numeric: tabular-nums; }
.u-sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ============================================================================
   MOVIMENTO REDUZIDO
   O style.css já tem um bloco global que zera animation/transition. Este bloco
   não confia nisso: neutraliza explicitamente cada efeito criado aqui e deixa
   os estados FINAIS corretos (o medidor tem que ficar preenchido, o confete
   tem que sumir, a celebração vira destaque estático).
   O hub-ui.js checa a mesma media query antes de animar em JS.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .tabs a,
  .toast,
  .hub-btn,
  .meter__fill { transition: none; }

  .stat-tile--live,
  .chip-streak.is-new,
  .skeleton::after,
  .celebrate.is-celebrating .celebrate__bloom { animation: none; }

  .stat-tile--live { box-shadow: inset 0 0 0 1px rgba(255, 196, 0, 0.40); }
  .skeleton::after { display: none; }
  .celebrate__bit { display: none; }
  .celebrate.is-celebrating .celebrate__bloom { opacity: 0.5; }
  .toast[data-state="enter"] { opacity: 1; transform: none; }
  .toast[data-state="exit"]  { opacity: 0; transform: none; }
}
