/**
 * Aprov.AI App — design tokens.
 * Fonte de verdade: ./DESIGN-SYSTEM-APP.md (v3, decidido).
 * Espelhado literalmente em ./app.tokens.ts. Editou um, edite o outro.
 *
 * Sistema INDEPENDENTE de ../tokens/tokens.css (o 07 exportado, papéis
 * Material 3), de ../web/web.tokens.css (--site-*) e de
 * ../social/social.tokens.css (--social-*). Nenhum hex é herdado. Os matizes
 * — esmeralda ~163°, coral ~9°, navy ~222° — e o par tipográfico são os
 * mesmos da marca; todos os valores são novos, calculados para sessão longa
 * e os dois temas.
 *
 * v3 (2026-10-19): Decisão 12 — esmeralda rara, CTA branco com brilho, escala
 * de 90%, escuro quase preto. "Se tudo é verde, nada chama atenção."
 *
 * v2 (2026-10-16): neutro grafite. A tela é cinza muito claro no matiz da
 * esmeralda contra grafite quase-preto; a cor da marca só aparece onde há
 * ação de compromisso ou pedido de atenção. Ver §Status → Decisão 8.
 *
 * ARQUITETURA DE TEMA — três blocos, não dois:
 *   :root                                   claro (o padrão)
 *   @media (prefers-color-scheme: dark)
 *     :root:not([data-theme="light"])       escuro por preferência do SO
 *   :root[data-theme="dark"]                escuro por escolha explícita
 * Sem o :not(), quem escolhe claro num sistema escuro não consegue.
 *
 * Nenhum nome de token cita luminosidade. É --app-surface, nunca
 * --app-surface-light; --app-action, nunca --app-graphite. O papel é estável,
 * só o valor troca de coluna — é isso que permite um tema novo sem renomear.
 *
 * Todo par texto/fundo aqui foi medido NOS DOIS TEMAS. Um par que passa no
 * claro e reprova no escuro é um par reprovado.
 */

:root {
  /* ══ SUPERFÍCIE ════════════════════════════════════════════════════════
   * O fundo é branco não absoluto, não cinza: off-white no matiz 160°, a
   * temperatura da esmeralda sem a sensação acinzentada do #F1F4F3 da v2.
   * O card continua branco puro; quem o descola do fundo é o hairline de
   * --app-border-raised, com a sombra difusa confirmando.
   * raised e overlay têm o mesmo valor no claro e valores diferentes no
   * escuro — por isso são dois tokens, não um. */
  --app-surface: #F8FAF9;
  --app-surface-sunken: #EEF2F0;
  --app-surface-raised: #FFFFFF;
  --app-surface-overlay: #FFFFFF;
  /* v3: o "selecionado sem pedir atenção" — linha atual do percurso, conversa
   * aberta. Opaco para o contraste ser medível; os *-mark medem ≥3:1 nele. */
  --app-surface-selected: #ECEFEE;
  --app-scrim: rgba(10, 14, 13, 0.48);
  color-scheme: light;

  /* ══ TEXTO ════════════════════════════════════════════════════════════
   * Grafite, não verde-escuro. O matiz continua lá, a croma saiu. */
  --app-ink: #141A18;
  --app-body: #3E4845;
  --app-muted: #5D6865;

  /* ══ AÇÃO NEUTRA ══════════════════════════════════════════════════════
   * O preenchimento grafite: a ação de fluxo (avançar, ver mais, confirmar
   * um passo). É o botão primário do sistema. No escuro ele INVERTE — vira
   * o claro sobre fundo escuro —, por isso o nome é o papel e não a cor. */
  --app-action: #1A211F;
  --app-action-hover: #2E3734;
  --app-on-action: #FFFFFF;

  /* ══ ACENTO ═══════════════════════════════════════════════════════════
   * v3 (Decisão 12): a esmeralda é RARA. Fica só em: o CTA de marca (um por
   * tela), acerto/domínio (--app-correct-*), o anel do nó atual do Mapa, o
   * foco e o Tutor (exceção deliberada: é a ferramenta que queremos ver
   * usada). Seleção de resposta, link e avatar são neutros.
   * v3.1 (Decisão 13): toques de volta — o item ativo da nav e da aba
   * (accent-selected + accent-ink) e o ícone de ornamento (accent, disco
   * neutro), exceto onde ele se repete em lista.
   * accent NUNCA é texto — é traço e ícone. Texto em esmeralda usa accent-ink.
   * O wash sobrevive para o raro bloco que é esmeralda de propósito. */
  --app-accent: #00976B;
  --app-accent-ink: #097758;
  --app-accent-deep: #0B4D3E;
  --app-accent-wash: #DDF7EC;
  --app-accent-selected: #DDF7EC;
  --app-on-accent: #FFFFFF;

  /* ══ MARCA (CTA de compromisso) ═══════════════════════════════════════
   * v3: substitui o degrau "vivo" #1FCF96 da v2.1. Esmeralda profunda com
   * texto BRANCO nos dois temas (4.65:1; hover 5.36:1). A vibração vem de
   * --app-shadow-brand (brilho interno + halo esmeralda), não de cor clara.
   * O hover escurece nos dois temas: clarear derrubaria o branco. */
  --app-brand: #00855E;
  --app-brand-hover: #007A56;
  --app-on-brand: #FFFFFF;

  /* ══ ATENÇÃO ══════════════════════════════════════════════════════════
   * Coral: aviso, novidade, prazo — o ponto de notificação e o selo "novo".
   * É o mesmo matiz de --app-wrong-*, e por isso tem regra de FORMA: atenção
   * é ponto ou selo, nunca contorno de alternativa; e aviso e revisão de
   * questão não dividem tela. `attention` é gráfico (≥3:1), nunca texto.
   * v2.1: #E0563F → #EC5A42, o coral mais claro que ainda mede ≥3:1 no
   * fundo off-white — um passo de volta em direção ao #FF6F59 da marca.
   * v3: #F04E35, mais saturado e com mais contraste (3.43 no fundo); wash com
   * mais croma. O ink fica: mais vermelho, encostaria no error-ink. */
  --app-attention: #F04E35;
  --app-attention-ink: #AD493B;
  --app-attention-wash: #FFE9E4;

  /* ══ FEEDBACK DE RESPOSTA ═════════════════════════════════════════════
   * "Trate reprovação como dado, não como vergonha" (03-Voz, regra 3).
   * Por isso ERRAR NÃO É VERMELHO: wrong é coral, a cor que a marca já usa
   * para ação humana. O vermelho --app-error é falha de SISTEMA — rede,
   * validação, indisponibilidade — e nunca toca uma questão respondida.
   * Cor nunca é o único portador do estado: ícone + rótulo, sempre.
   * *-mark (v2.1): a versão GRÁFICA do estado — ponto do semáforo, traço.
   * O ink foi escurecido para 4.5:1 de texto; um ponto com rótulo ao lado
   * só precisa de 3:1, e pintá-lo de ink deixava o semáforo marrom e morto.
   * Cada mark mede ≥3:1 no card, no fundo e no surface-selected (v3: a linha atual
   * do percurso). */
  --app-correct-ink: #097758;
  --app-correct-wash: #DDF7EC;
  --app-correct-mark: #009B6C;
  --app-wrong-ink: #AD493B;
  --app-wrong-wash: #FFE9E4;
  --app-blank-ink: #4C5A55;
  --app-blank-wash: #EEF2F0;
  --app-annulled-ink: #7D5200;
  --app-annulled-wash: #F6EFE2;
  /* Domínio parcial de um tema, no semáforo do Mapa. Fica no dourado e não
   * no coral de propósito: `partial` e `wrong` aparecem lado a lado numa
   * trilha, e precisam se distinguir à primeira leitura. A proximidade com
   * `annulled` é aceita — os dois nunca dividem tela (v3: o wash de annulled
   * ficou mais neutro para separar os dois mesmo assim).
   * v3: partial-fill é o âmbar VIVO do ponto e da barra. Sozinho mede 2.14:1,
   * por isso nunca aparece sem o anel de 1px em partial-ink (6.19:1), que é
   * quem carrega o contraste gráfico. partial-mark fica como traço sem anel. */
  --app-partial-ink: #855800;
  --app-partial-wash: #FFF0D6;
  --app-partial-mark: #BF7300;
  --app-partial-fill: #F2A007;

  /* ══ DESAFIO BÔNUS ════════════════════════════════════════════════════
   * A única família de cor do app que NÃO fala de desempenho. Existe porque
   * o desafio surpresa do Mapa precisa se distinguir dos quatro estados de
   * resposta à primeira leitura — pintá-lo de esmeralda o faria ler como
   * "acertou", e de âmbar como "em construção". Violeta não colide com
   * nenhum deles e não carrega juízo sobre o aluno.
   * NÃO é um quinto estado de feedback: nunca aparece numa questão
   * respondida, só num convite que o motor montou. */
  --app-bonus-ink: #5A3EC2;
  --app-bonus-wash: #F0EBFF;

  /* Tema escapando da memória: dominado antes, mas a lembrança caiu. Azul-aço,
   * e não partial: o aluno sabia — o que se perde é o tempo, não o domínio.
   * Só no Mapa e no Mapa de Domínio 3D, como partial. Nunca vermelho. */
  --app-fading-ink: #1D5DA3;
  --app-fading-wash: #E3EEFF;
  --app-fading-mark: #1F78F0;

  /* ══ ERRO DE SISTEMA ══════════════════════════════════════════════════ */
  --app-error-ink: #B3261E;
  --app-error-wash: #FCE9E7;
  --app-on-error: #FFFFFF;

  /* ══ CAMPO ════════════════════════════════════════════════════════════ */
  --app-field-bg: #FFFFFF;
  --app-field-bg-disabled: #EEF2F0;
  --app-field-placeholder: #5F6A67;
  --app-field-ring: rgba(20, 26, 24, 0.22);
  --app-field-ring-hover: rgba(20, 26, 24, 0.38);
  --app-field-ring-focus: #097758;
  --app-field-ring-error: #B3261E;
  /* v3: o chevron do select. Data-URI porque <select> não aceita pseudo-
   * elemento; o traço é o --app-muted do tema (check-contrast.py trava isso).
   * Sem `;` e sem `#` cru dentro do url(). */
  --app-select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235D6865' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");

  /* ══ TRAÇO E VÉU ══════════════════════════════════════════════════════ */
  --app-hairline: rgba(20, 26, 24, 0.10);
  --app-hairline-soft: rgba(20, 26, 24, 0.06);
  --app-ring: rgba(20, 26, 24, 0.16);
  --app-ring-hover: rgba(20, 26, 24, 0.28);
  --app-veil: rgba(20, 26, 24, 0.05);
  --app-veil-strong: rgba(20, 26, 24, 0.09);

  /* ══ NAVEGAÇÃO FLUTUANTE ══════════════════════════════════════════════
   * A pílula do bottom nav. No claro é o mesmo grafite da ação; o item ativo
   * é um círculo de superfície com o ícone em tinta. No escuro o nav vira um
   * degrau acima do overlay e quem o descola do fundo é o contorno. */
  --app-nav-bg: #1A211F;
  --app-on-nav: #C4CCC9;
  --app-nav-active-bg: #FFFFFF;
  --app-on-nav-active: #141A18;

  /* ══ ROLAGEM ══════════════════════════════════════════════════════════
   * As duas cores são ALIAS, não valores novos: um polegar de rolagem pesa
   * exatamente o que pesa um contorno secundário, e a escada de alfa deste
   * sistema (véu .05 → véu-forte .09 → hairline .10 → ring .16 → ring-hover
   * .28) não precisa de um sexto degrau para dizer a mesma coisa.
   *
   * Por serem `var()`, resolvem no tema em vigor — os três blocos de :root
   * seguem sendo a única fonte de verdade, e este grupo se declara uma vez só.
   * Ver §Componentes → Barra de rolagem. */
  --app-scroll-size: 12px;
  --app-scroll-inset: 3px;
  --app-scroll-thumb: var(--app-ring);
  --app-scroll-thumb-hover: var(--app-ring-hover);

  /* ══ SÉRIE DE GRÁFICO ═════════════════════════════════════════════════
   * Escada de luminância: degraus adjacentes ≥1.35x em escala de cinza, e
   * ≥40 de distância sob deuteranopia, protanopia e tritanopia. Os três
   * primeiros são os matizes da marca e cobrem o uso real; 4 e 5 só existem
   * para quando cinco séries são inevitáveis. Ver o teto em §Dado. */
  /* chart-1 NAO acompanha o --app-accent da v2 (#00976B): escurecida, a
   * esmeralda cairia a 1.31x de chart-4 em escala de cinza e quebraria a
   * escada. Grafico vive em card (raised), onde #00A072 mede 3.35:1. */
  --app-chart-1: #00A072;
  --app-chart-2: #243C78;
  --app-chart-3: #A8331C;
  --app-chart-4: #BF4086;
  --app-chart-5: #132A2E;
  --app-chart-grid: rgba(20, 26, 24, 0.09);
  --app-pattern-grid:
    linear-gradient(to right, rgba(20, 26, 24, 0.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(20, 26, 24, 0.05) 1px, transparent 1px);

  /* ══ ELEVAÇÃO ═════════════════════════════════════════════════════════
   * No claro, sombra larga e quase transparente mais um hairline de 6%: o
   * fundo off-white é claro demais para o card existir só por luminância,
   * e card dependendo só de sombra é o anti-padrão da v1. No escuro a sombra some e quem separa é a
   * superfície mais clara + o contorno — sombra preta sobre fundo preto é
   * card invisível. O componente nunca escolhe entre um e outro.
   * action: o botão grafite tem sombra própria, curta e mais densa.
   * float: o que paira sobre o conteúdo rolando (bottom nav, FAB).
   * *-hover: o mesmo degrau, um pouco mais alto, pro card e o botão que
   * sobem sob o ponteiro. Hover TROCA o token, nunca soma outro. */
  --app-shadow-raised: 0 1px 2px rgba(20, 26, 24, 0.04), 0 8px 24px rgba(20, 26, 24, 0.06);
  --app-shadow-raised-hover: 0 2px 4px rgba(20, 26, 24, 0.05), 0 14px 32px rgba(20, 26, 24, 0.10);
  --app-shadow-overlay: 0 12px 24px rgba(20, 26, 24, 0.10), 0 32px 64px rgba(20, 26, 24, 0.14);
  --app-shadow-action: 0 6px 16px rgba(20, 26, 24, 0.20);
  --app-shadow-action-hover: 0 10px 24px rgba(20, 26, 24, 0.24);
  --app-shadow-float: 0 12px 32px rgba(20, 26, 24, 0.24);
  /* v3: brand é a ÚNICA sombra colorida do sistema. Brilho interno de 1px no
   * topo + halo esmeralda. Cada token é a lista inteira — sombra nunca se
   * compõe (no escuro raised vira `none`, e `none, inset …` é inválido). */
  --app-shadow-brand: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 1px 2px rgba(0, 77, 54, 0.20), 0 6px 18px rgba(0, 133, 94, 0.28);
  --app-shadow-brand-hover: inset 0 1px 0 rgba(255, 255, 255, 0.20), 0 2px 4px rgba(0, 77, 54, 0.20), 0 10px 28px rgba(0, 133, 94, 0.36);
  /* O card de destaque neutro (Sugestão de hoje): a receita do raised com um
   * contorno mais firme. Quem destaca é o CTA de marca dentro dele. */
  --app-shadow-highlight: 0 1px 2px rgba(20, 26, 24, 0.04), 0 8px 24px rgba(20, 26, 24, 0.06), inset 0 0 0 1px rgba(20, 26, 24, 0.28);
  /* A porta do Tutor (exceção verde deliberada). No claro: aro fino, halo
   * translúcido e luz esmeralda suave — o wash chapado lia como borrão. */
  --app-shadow-tutor: inset 0 0 0 1px rgba(0, 151, 107, 0.55), 0 0 0 3px rgba(0, 151, 107, 0.10), 0 1px 2px rgba(20, 26, 24, 0.06), 0 6px 18px rgba(0, 151, 107, 0.20);
  --app-shadow-tutor-hover: inset 0 0 0 1px rgba(0, 151, 107, 0.70), 0 0 0 3px rgba(0, 151, 107, 0.14), 0 1px 2px rgba(20, 26, 24, 0.06), 0 8px 24px rgba(0, 151, 107, 0.28);
  --app-border-raised: 1px solid rgba(20, 26, 24, 0.06);
  --app-border-overlay: 1px solid transparent;
  --app-border-float: 1px solid transparent;

  /* ══ TIPOGRAFIA ═══════════════════════════════════════════════════════
   * Duas famílias, nenhuma terceira. A troca nunca é decorativa: se está em
   * display, é título ou dado. */
  --app-font-display: 'Plus Jakarta Sans', system-ui, sans-serif;
  --app-font-body: 'Work Sans', system-ui, sans-serif;

  /* v3: escala de 90% (o zoom de 90% do browser era a referência). O
   * enunciado fica em 16: é texto clínico, lido sob cansaço. Piso: 11 só no
   * label (600, caixa-alta); caption 12 é o menor texto corrido. Texto pequeno
   * abre tracking e leading; display mantém o tracking negativo. */
  --app-type-headline-size: clamp(22px, 2.5vw, 28px);
  --app-type-headline-lh: 1.2;
  --app-type-headline-weight: 700;
  --app-type-headline-track: -0.02em;

  --app-type-title-size: 18px;
  --app-type-title-lh: 1.33;
  --app-type-title-weight: 700;
  --app-type-title-track: -0.01em;

  /* subtitle: na v3 é também o TÍTULO DE LINHA (.linha-titulo). */
  --app-type-subtitle-size: 15px;
  --app-type-subtitle-lh: 1.4;
  --app-type-subtitle-weight: 600;

  /* stem: o enunciado da questão. Único papel com line-height 1.7 — é texto
   * clínico longo, lido sob cansaço, e o respiro entre linhas é o que
   * impede o olho de pular linha na volta. */
  --app-type-stem-size: 16px;
  --app-type-stem-lh: 1.7;
  --app-type-stem-weight: 400;
  --app-type-stem-measure: 72ch;

  --app-type-body-size: 15px;
  --app-type-body-lh: 1.6;
  --app-type-body-measure: 68ch;

  --app-type-body-sm-size: 14px;
  --app-type-body-sm-lh: 1.43;

  --app-type-caption-size: 12px;
  --app-type-caption-lh: 1.5;
  --app-type-caption-track: 0.005em;

  --app-type-label-size: 11px;
  --app-type-label-lh: 1.25;
  --app-type-label-weight: 600;
  --app-type-label-track: 0.09em;

  /* Campo em toque: abaixo de 16px o Safari do iOS dá zoom no foco. */
  --app-type-field-touch-size: 16px;

  /* Número: sempre display 700 + tabular-nums. Sem tabular o cronômetro
   * dança a cada segundo virado e a coluna de nota desalinha. */
  --app-type-data-xl-size: clamp(30px, 4.5vw, 42px);
  --app-type-data-xl-lh: 1.0;
  --app-type-data-xl-track: -0.03em;
  --app-type-data-lg-size: 28px;
  --app-type-data-lg-lh: 1.1;
  --app-type-data-lg-track: -0.02em;
  --app-type-data-md-size: 22px;
  --app-type-data-md-lh: 1.15;
  --app-type-data-md-track: -0.01em;
  --app-type-data-sm-size: 16px;
  --app-type-data-sm-lh: 1.25;

  /* ══ ESPAÇO ═══════════════════════════════════════════════════════════
   * Baseline de 8. v2: o app é arejado — o degrau útil subiu para 24–56,
   * com UMA exceção, a tela de questão, onde as alternativas ficam a 12px
   * para caber sem rolagem. A escala não mudou; o que mudou é qual degrau
   * cada papel usa, e esses papéis agora têm nome (abaixo). */
  --app-space-3xs: 2px;
  --app-space-2xs: 4px;
  --app-space-xs: 8px;
  --app-space-sm: 12px;
  --app-space-md: 16px;
  --app-space-lg: 20px;
  --app-space-xl: 24px;
  --app-space-2xl: 32px;
  --app-space-3xl: 40px;
  --app-space-4xl: 56px;
  --app-space-5xl: 64px;

  /* Ritmo semântico. Componente usa estes, não o degrau cru, quando o papel
   * existe aqui — é o que permite reajustar o respiro sem caçar px. */
  --app-pad-card: 24px;
  --app-pad-card-md: 32px;
  --app-gap-option: 12px;
  --app-gap-block: 32px;
  --app-gap-section: 40px;
  --app-gap-section-md: 56px;

  /* v3: ritmo de molécula e de lista. A hierarquia é estrita —
   * 2 (dentro da molécula) < 4 (entre linhas) < 12 (guia ↔ texto) <
   * 16 (dentro do card) < 16–20 (entre cards) < 32 (entre seções).
   * Texto menor + vão entre moléculas maior = o respiro da Decisão 12. */
  --app-gap-stack: 2px;
  --app-gap-list: 4px;
  --app-gap-inline: 12px;
  /* A linha sangra: padding-x = o quanto o fundo do hover/seleção sai para
   * fora da borda do conteúdo (margin-inline negativa do mesmo valor). */
  --app-row-pad-x: 12px;
  --app-row-pad-y: 12px;
  --app-row-pad-y-divided: 16px;
  --app-gap-card: 16px;
  --app-gap-grid: 16px;
  --app-gap-grid-md: 20px;
  --app-pad-tile: 16px;

  /* ══ DENSIDADE E ALVO ═════════════════════════════════════════════════
   * control-sm é a MENOR caixa visível, não o menor alvo. O alvo tocável
   * nunca desce de 44px — a área invisível cresce por padding, a caixa não.
   * v2: um degrau acima em toda a escada. Pílula baixa lê como etiqueta.
   * v3: a escada acompanha o texto de 90% (36/44/52). O alvo tocável segue
   * 44 — em toque, row-compact sobe a 44 (bloco pointer:coarse no fim). */
  --app-control-sm: 36px;
  --app-control-md: 44px;
  --app-control-lg: 52px;
  --app-touch-min: 44px;
  --app-chip-h: 24px;
  --app-row-compact: 36px;
  --app-row: 44px;
  --app-row-comfortable: 52px;

  /* ══ LAYOUT ═══════════════════════════════════════════════════════════ */
  --app-bp-sm: 480px;
  --app-bp-md: 768px;
  --app-bp-lg: 1024px;
  --app-bp-xl: 1280px;
  --app-gutter: 20px;
  --app-gutter-md: 32px;
  --app-content-max: 1200px;
  --app-reading-max: 720px;
  --app-sidebar: 240px;
  --app-header-h: 56px;
  --app-bottom-nav-h: 64px;
  --app-bottom-nav-inset: 16px;

  /* ══ RAIO ═════════════════════════════════════════════════════════════
   * v2: generoso. Todo CONTROLE é pílula (botão, chip, tab, busca) ou
   * círculo (botão de ícone) — r-btn é 999px, então qualquer .btn vira
   * pílula pelo token. Todo BLOCO é arredondado e nunca pílula: card,
   * alternativa e diálogo carregam texto de várias linhas, e pílula com
   * texto quebrando deforma. Campo de formulário fica no meio. */
  --app-r-xs: 10px;
  --app-r-field: 14px;
  --app-r-btn: 999px;
  --app-r-option: 20px;
  --app-r-card: 24px;
  --app-r-modal: 28px;
  --app-r-pill: 999px;
  /* O nó do Mapa. Flutua sobre o quadriculado em vez de assentar numa
   * superfície, e o raio solto é o que o faz ler como objeto num espaço. */
  --app-r-node: 28px;

  /* ══ QUADRICULADO ═════════════════════════════════════════════════════
   * O fundo da marca (mesma malha de 40px de Brand/assets). Chega ao app
   * para o Mapa: o trilho precisa de um espaço que se leia como "área de
   * navegação", e não como mais uma superfície de conteúdo. A malha é
   * SEMPRE decorativa — nenhuma informação vive nela. */
  --app-pattern-grid-size: 40px 40px;

  /* ══ ÍCONE ════════════════════════════════════════════════════════════
   * Escala do 07 preservada. Cor é sempre currentColor — ícone com cor
   * própria é ícone que quebra ao trocar de tema. */
  --app-icon-sm: 16px;
  --app-icon-md: 18px;
  --app-icon-lg: 22px;
  --app-icon-xl: 28px;
  --app-icon-stroke: 2;

  /* ══ FOCO ═════════════════════════════════════════════════════════════
   * 2px sólido com 2px de offset em TODO alvo interativo. Não existe
   * outline:none neste sistema. */
  --app-focus-width: 2px;
  --app-focus-offset: 2px;
  --app-focus-color: #097758;

  /* ══ MOTION ═══════════════════════════════════════════════════════════ */
  --app-duration-fast: 120ms;
  --app-duration-base: 200ms;
  --app-duration-slow: 320ms;
  --app-ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  --app-ease-emphasized: cubic-bezier(0.2, 0, 0, 1);
  /* Elevação sob o ponteiro: controle sobe 1px, card sobe 2px. No press
   * tudo desce de volta e o controle encolhe um pouco — o card não, porque
   * 3% de um card largo é um tranco. Movem por `translate`/`scale`, nunca
   * por `transform`, pra não brigar com animação de entrada nem com giro. */
  --app-lift-control: -1px;
  --app-lift-card: -2px;
  --app-press-scale: 0.97;

  /* ══ OPACIDADE ════════════════════════════════════════════════════════ */
  --app-opacity-disabled: 0.45;

  /* ══ Z-INDEX ══════════════════════════════════════════════════════════ */
  --app-z-header: 10;
  --app-z-sidebar: 20;
  --app-z-dropdown: 30;
  --app-z-scrim: 40;
  --app-z-modal: 41;
  --app-z-toast: 50;
}

/* ═══════════════════════════════════════════════════════════════════════
 * TEMA ESCURO
 * O 07 registra "nunca dark mode". A v1 REVOGOU essa regra no escopo app
 * e só nele: Camila e Fernando estudam em plantão e de madrugada, e a
 * decisão original do 07 foi tomada para superfície de marketing, não para
 * ferramenta de sessão longa. A landing e o social seguem claros.
 *
 * v2: grafite neutro, no mesmo matiz do claro. A ação inverte — o botão
 * primário é claro com texto escuro.
 * v3: quase preto (matiz 150–160, saturação 6–9%) e sem wash verde fora de
 * atenção. O wash de acento caiu de #102C24 para #111B17; o de acerto fica.
 *
 * Os dois blocos abaixo são idênticos de propósito: o primeiro atende a
 * preferência do sistema, o segundo a escolha explícita dentro do app. O
 * :not() do primeiro é o que permite escolher claro num SO escuro.
 * ═══════════════════════════════════════════════════════════════════════ */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --app-surface: #0A0C0B;
    --app-surface-sunken: #060807;
    --app-surface-raised: #121514;
    --app-surface-overlay: #191D1B;
    --app-surface-selected: #222826;
    --app-scrim: rgba(0, 0, 0, 0.66);

    --app-ink: #F1F4F3;
    --app-body: #C4CCC9;
    --app-muted: #99A4A0;

    --app-action: #E8EDEB;
    --app-action-hover: #FFFFFF;
    --app-on-action: #141A18;

    --app-accent: #3DE0A8;
    --app-accent-ink: #5FE3B4;
    --app-accent-deep: #8FEDCC;
    --app-accent-wash: #111B17;
    --app-accent-selected: #11281F;
    --app-on-accent: #04231B;

    /* Marca: o mesmo preenchimento do claro. Texto branco mede 4.65:1; o
     * botão contra o quase-preto mede 4.22 (fundo) e 3.95 (card). */
    --app-brand: #00855E;
    --app-brand-hover: #007A56;
    --app-on-brand: #FFFFFF;

    --app-attention: #FF8A73;
    --app-attention-ink: #FF9D88;
    --app-attention-wash: #33201C;

    --app-correct-ink: #5FE3B4;
    --app-correct-wash: #102C24;
    --app-correct-mark: #3DE0A8;
    --app-wrong-ink: #FF9D88;
    --app-wrong-wash: #33201C;
    --app-blank-ink: #A3B5AF;
    --app-blank-wash: #1C201E;
    --app-annulled-ink: #F0C878;
    --app-annulled-wash: #2E2415;
    --app-partial-ink: #EFC77F;
    --app-partial-mark: #EFC77F;
    --app-partial-fill: #EFC77F;
    --app-partial-wash: #2C2416;

    /* Desafio bônus. Não é estado de resposta — ver o bloco no tema claro. */
    --app-bonus-ink: #C7B8FF;
    --app-bonus-wash: #221C3A;
    --app-fading-ink: #9CC4EC;
    --app-fading-mark: #9CC4EC;
    --app-fading-wash: #17222E;

    --app-error-ink: #FF9E96;
    --app-error-wash: #341A18;
    --app-on-error: #2E0B09;

    --app-field-bg: #0A0C0B;
    --app-field-bg-disabled: #101312;
    --app-field-placeholder: #8F9A96;
    --app-field-ring: rgba(241, 244, 243, 0.20);
    --app-field-ring-hover: rgba(241, 244, 243, 0.36);
    --app-field-ring-focus: #5FE3B4;
    --app-field-ring-error: #FF9E96;
    --app-select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2399A4A0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");

    --app-hairline: rgba(241, 244, 243, 0.12);
    --app-hairline-soft: rgba(241, 244, 243, 0.07);
    --app-ring: rgba(241, 244, 243, 0.18);
    --app-ring-hover: rgba(241, 244, 243, 0.32);
    --app-veil: rgba(241, 244, 243, 0.06);
    --app-veil-strong: rgba(241, 244, 243, 0.11);

    --app-nav-bg: #1C201E;
    --app-on-nav: #C4CCC9;
    --app-nav-active-bg: #F1F4F3;
    --app-on-nav-active: #141A18;

    --app-chart-1: #3DE0A8;
    --app-chart-2: #E0E7F6;
    --app-chart-3: #E35138;
    --app-chart-4: #F57FC0;
    --app-chart-5: #3C737E;
    --app-chart-grid: rgba(241, 244, 243, 0.10);
    --app-pattern-grid:
      linear-gradient(to right, rgba(255, 255, 255, 0.03) 1px, transparent 1px),
      linear-gradient(to bottom, rgba(255, 255, 255, 0.03) 1px, transparent 1px);

    /* Sombra preta sobre fundo preto não separa nada. No escuro a elevação
     * é a superfície mais clara + o contorno; a sombra de card é desligada.
     * v3: o primário ganha um bisel (fecha a Lacuna 14); a marca é a única
     * luz colorida, e o Tutor congela o visual da v2.1, aprovado no escuro. */
    --app-shadow-raised: none;
    --app-shadow-raised-hover: none;
    --app-shadow-overlay: 0 16px 48px rgba(0, 0, 0, 0.56);
    --app-shadow-action: inset 0 -1px 0 rgba(10, 12, 11, 0.18);
    --app-shadow-action-hover: inset 0 -1px 0 rgba(10, 12, 11, 0.18);
    --app-shadow-float: 0 16px 40px rgba(0, 0, 0, 0.50);
    --app-shadow-brand: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 0 0 1px rgba(61, 224, 168, 0.18), 0 8px 24px rgba(0, 133, 94, 0.40);
    --app-shadow-brand-hover: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 0 0 1px rgba(61, 224, 168, 0.26), 0 10px 32px rgba(0, 133, 94, 0.52);
    --app-shadow-highlight: inset 0 0 0 1px rgba(241, 244, 243, 0.32);
    --app-shadow-tutor: inset 0 0 0 1.5px #3DE0A8, 0 0 0 4px #102C24, 0 6px 20px rgba(61, 224, 168, 0.22);
    --app-shadow-tutor-hover: inset 0 0 0 1.5px #3DE0A8, 0 0 0 4px #102C24, 0 6px 20px rgba(61, 224, 168, 0.32);
    --app-border-raised: 1px solid rgba(241, 244, 243, 0.10);
    --app-border-overlay: 1px solid rgba(241, 244, 243, 0.14);
    --app-border-float: 1px solid rgba(241, 244, 243, 0.12);

    --app-focus-color: #5FE3B4;
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --app-surface: #0A0C0B;
  --app-surface-sunken: #060807;
  --app-surface-raised: #121514;
  --app-surface-overlay: #191D1B;
  --app-surface-selected: #222826;
  --app-scrim: rgba(0, 0, 0, 0.66);

  --app-ink: #F1F4F3;
  --app-body: #C4CCC9;
  --app-muted: #99A4A0;

  --app-action: #E8EDEB;
  --app-action-hover: #FFFFFF;
  --app-on-action: #141A18;

  --app-accent: #3DE0A8;
  --app-accent-ink: #5FE3B4;
  --app-accent-deep: #8FEDCC;
  --app-accent-wash: #111B17;
  --app-accent-selected: #11281F;
  --app-on-accent: #04231B;

  /* Marca: o mesmo preenchimento do claro. Texto branco mede 4.65:1; o
   * botão contra o quase-preto mede 4.22 (fundo) e 3.95 (card). */
  --app-brand: #00855E;
  --app-brand-hover: #007A56;
  --app-on-brand: #FFFFFF;

  --app-attention: #FF8A73;
  --app-attention-ink: #FF9D88;
  --app-attention-wash: #33201C;

  --app-correct-ink: #5FE3B4;
  --app-correct-wash: #102C24;
  --app-correct-mark: #3DE0A8;
  --app-wrong-ink: #FF9D88;
  --app-wrong-wash: #33201C;
  --app-blank-ink: #A3B5AF;
  --app-blank-wash: #1C201E;
  --app-annulled-ink: #F0C878;
  --app-annulled-wash: #2E2415;
  --app-partial-ink: #EFC77F;
  --app-partial-mark: #EFC77F;
  --app-partial-fill: #EFC77F;
  --app-partial-wash: #2C2416;

  /* Desafio bônus. Não é estado de resposta — ver o bloco no tema claro. */
  --app-bonus-ink: #C7B8FF;
  --app-bonus-wash: #221C3A;
  --app-fading-ink: #9CC4EC;
  --app-fading-mark: #9CC4EC;
  --app-fading-wash: #17222E;

  --app-error-ink: #FF9E96;
  --app-error-wash: #341A18;
  --app-on-error: #2E0B09;

  --app-field-bg: #0A0C0B;
  --app-field-bg-disabled: #101312;
  --app-field-placeholder: #8F9A96;
  --app-field-ring: rgba(241, 244, 243, 0.20);
  --app-field-ring-hover: rgba(241, 244, 243, 0.36);
  --app-field-ring-focus: #5FE3B4;
  --app-field-ring-error: #FF9E96;
  --app-select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2399A4A0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");

  --app-hairline: rgba(241, 244, 243, 0.12);
  --app-hairline-soft: rgba(241, 244, 243, 0.07);
  --app-ring: rgba(241, 244, 243, 0.18);
  --app-ring-hover: rgba(241, 244, 243, 0.32);
  --app-veil: rgba(241, 244, 243, 0.06);
  --app-veil-strong: rgba(241, 244, 243, 0.11);

  --app-nav-bg: #1C201E;
  --app-on-nav: #C4CCC9;
  --app-nav-active-bg: #F1F4F3;
  --app-on-nav-active: #141A18;

  --app-chart-1: #3DE0A8;
  --app-chart-2: #E0E7F6;
  --app-chart-3: #E35138;
  --app-chart-4: #F57FC0;
  --app-chart-5: #3C737E;
  --app-chart-grid: rgba(241, 244, 243, 0.10);
  --app-pattern-grid:
    linear-gradient(to right, rgba(255, 255, 255, 0.03) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, 0.03) 1px, transparent 1px);

  /* Sombra preta sobre fundo preto não separa nada. No escuro a elevação
   * é a superfície mais clara + o contorno; a sombra de card é desligada.
   * v3: o primário ganha um bisel (fecha a Lacuna 14); a marca é a única
   * luz colorida, e o Tutor congela o visual da v2.1, aprovado no escuro. */
  --app-shadow-raised: none;
  --app-shadow-raised-hover: none;
  --app-shadow-overlay: 0 16px 48px rgba(0, 0, 0, 0.56);
  --app-shadow-action: inset 0 -1px 0 rgba(10, 12, 11, 0.18);
  --app-shadow-action-hover: inset 0 -1px 0 rgba(10, 12, 11, 0.18);
  --app-shadow-float: 0 16px 40px rgba(0, 0, 0, 0.50);
  --app-shadow-brand: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 0 0 1px rgba(61, 224, 168, 0.18), 0 8px 24px rgba(0, 133, 94, 0.40);
  --app-shadow-brand-hover: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 0 0 1px rgba(61, 224, 168, 0.26), 0 10px 32px rgba(0, 133, 94, 0.52);
  --app-shadow-highlight: inset 0 0 0 1px rgba(241, 244, 243, 0.32);
  --app-shadow-tutor: inset 0 0 0 1.5px #3DE0A8, 0 0 0 4px #102C24, 0 6px 20px rgba(61, 224, 168, 0.22);
  --app-shadow-tutor-hover: inset 0 0 0 1.5px #3DE0A8, 0 0 0 4px #102C24, 0 6px 20px rgba(61, 224, 168, 0.32);
  --app-border-raised: 1px solid rgba(241, 244, 243, 0.10);
  --app-border-overlay: 1px solid rgba(241, 244, 243, 0.14);
  --app-border-float: 1px solid rgba(241, 244, 243, 0.12);

  --app-focus-color: #5FE3B4;
}

/* Reduced motion: o lift e o press viram zero na fonte. Encurtar a duração
 * (regra global do app) ainda deixaria o card pular 2px de uma vez. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --app-lift-control: 0px;
    --app-lift-card: 0px;
    --app-press-scale: 1;
  }
}

/* Toque: o alvo nunca desce de 44. Linhas sem ::after de toque (nav, menu,
 * escolha) usam row-compact, que aqui sobe ao touch-min. Fica DEPOIS dos
 * blocos escuros: o check-contrast.py compara só os dois blocos de tema. */
@media (pointer: coarse) {
  :root {
    --app-row-compact: var(--app-touch-min);
  }
}
