/* ===========================================================================
   CheckInGYM — Prime Fight Club
   ---------------------------------------------------------------------------
   Tema claro por omissão — mesmo para quem tem o sistema em modo escuro.
   O escuro existe, mas exige uma escolha (ver o botão de tema).

   A marca do Prime Fight Club é preto e branco. Isso não é uma limitação: é o
   que deixa TODA a cor livre para significar uma coisa só — o estado do
   pagamento. A moldura (barra lateral, barra inferior) é preta e é onde a
   marca vive; o conteúdo é claro e é onde os estados vivem. Como nunca
   partilham o mesmo espaço, nunca competem, e o vermelho quer dizer sempre, e
   só, que alguém deve dinheiro.

   As cores de estado não foram escolhidas a olho. Verde, âmbar e vermelho
   colapsam quase todos no mesmo tom sob daltonismo vermelho-verde, que é a
   forma mais comum — por isso quem faz o trabalho de os separar é a
   LUMINOSIDADE, e os valores foram medidos até passarem:

     · separação sob protanopia e deuteranopia (ΔE ≥ 8)
     · piso de visão normal (ΔE ≥ 15 entre estados vizinhos)
     · contraste ≥ 3:1 contra a superfície de cada tema

   Além disso, nenhum estado é comunicado só por cor: há sempre a palavra
   ("Em dia", "Em atraso") ao lado da cor.

   Tipografia alojada no próprio servidor: a política de segurança bloqueia
   pedidos a terceiros, e o check-in tem de abrir sem rede nenhuma.
   =========================================================================== */

@font-face {
    font-family: 'Inter';
    src: url('/fontes/inter.woff2') format('woff2');
    font-weight: 400 900;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Anton';
    src: url('/fontes/anton.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

/* --- Tokens: tema claro (omissão) ---------------------------------------- */

:root {
    color-scheme: light;

    --fundo: #f6f7f6;
    --superficie: #ffffff;
    --superficie-2: #f1f3f2;
    --superficie-3: #e8ebe9;
    --linha: #e4e7e5;
    --linha-forte: #d0d5d2;

    --texto: #101413;
    --texto-2: #545c58;
    --texto-3: #79817d;

    /* A marca é a tinta. Botões primários pretos com texto branco são ao mesmo
       tempo o Prime Fight Club e a convenção mais séria para uma ação
       principal — e deixam o verde livre para dizer só "está em dia". */
    --marca: #16191a;
    --marca-2: #000000;
    --marca-tenue: #f0f1f1;
    --marca-texto: #ffffff;

    /* A moldura escura, que não muda com o tema: é a identidade. */
    --moldura: #0c0d0d;
    --moldura-2: #17191a;
    --moldura-3: #232627;
    --moldura-linha: #262a2b;
    --moldura-texto: #f4f6f5;
    --moldura-texto-2: #9aa2a1;

    --pago: #0b6b3a;
    --pago-tenue: #eaf5ef;
    --pago-linha: #b9dfc9;

    --vencer: #c98a00;
    --vencer-tenue: #fdf3e0;
    --vencer-linha: #f0d9a8;

    --atraso: #c0203a;
    --atraso-tenue: #fdeced;
    --atraso-linha: #f3c3c9;

    --neutro: #6b736f;
    --neutro-tenue: #f1f3f2;
    --neutro-linha: #dde1df;

    /* Marcas dos gráficos. Cada gráfico tem uma série só, por isso não há
       identidade a codificar — o título diz o que é. O verde é o pulso do
       ginásio; o dinheiro fica em tinta neutra, porque é um facto, não um
       estado. */
    --marca-grafico: #0b6b3a;
    --marca-grafico-2: #4a5450;
    --grelha: #eceeed;

    --sombra-1: 0 1px 2px rgba(16, 20, 19, 0.05);
    --sombra-2: 0 1px 3px rgba(16, 20, 19, 0.07), 0 4px 12px -4px rgba(16, 20, 19, 0.07);
    --sombra-3: 0 12px 32px -12px rgba(16, 20, 19, 0.25);

    --raio: 12px;
    --raio-p: 8px;
    --raio-g: 18px;

    --e1: 4px;
    --e2: 8px;
    --e3: 12px;
    --e4: 16px;
    --e5: 24px;
    --e6: 32px;
    --e7: 48px;
    --e8: 72px;

    --display: 'Anton', 'Haettenschweiler', 'Arial Narrow', Impact, sans-serif;
    --corpo: 'Inter', 'Segoe UI Variable', 'Segoe UI', system-ui, -apple-system, sans-serif;

    /* Curvas com arranque forte. Nunca `ease-in` em interface: começar devagar
       é exatamente o momento em que a pessoa está a olhar, e parece hesitação. */
    --saida: cubic-bezier(0.23, 1, 0.32, 1);
    --entrada-saida: cubic-bezier(0.77, 0, 0.175, 1);
}

/* --- Tokens: tema escuro -------------------------------------------------- */
/*
   O escuro NÃO vem da preferência do sistema por si só.

   Quase toda a gente tem o telemóvel em modo escuro, e com
   `@media (prefers-color-scheme: dark)` sozinho essas pessoas nunca chegavam a
   ver o tema claro — que é o que esta aplicação usa por omissão. Por isso o
   escuro exige uma escolha: `data-tema="escuro"`, ou `data-tema="auto"` para
   quem quiser mesmo seguir o sistema. O atributo é posto por `js/tema.js`.

   Os tons não são uma inversão automática do claro: foram escolhidos e medidos
   outra vez contra a superfície escura, porque um verde que funciona em papel
   branco fica a brilhar como néon em fundo preto. */

/* Um só bloco, e uma só forma de o ativar: o atributo.
   "Seguir o sistema" também acaba aqui — quem lê a preferência do browser é o
   `js/tema.js`, que traduz a escolha para este mesmo atributo. Assim a folha de
   estilos tem os valores escuros escritos uma vez, e não duas listas iguais à
   espera de divergirem. */

:root[data-tema='escuro'] {
    color-scheme: dark;

    --fundo: #0e1211;
    --superficie: #161a18;
    --superficie-2: #1c2220;
    --superficie-3: #242b28;
    --linha: #262e2b;
    --linha-forte: #38423e;

    --texto: #eef2f0;
    --texto-2: #a2aca7;
    --texto-3: #79837e;

    /* No escuro, um botão preto sobre fundo escuro desaparecia: a ação
       principal inverte-se e passa a ser clara. */
    --marca: #eef2f0;
    --marca-2: #ffffff;
    --marca-tenue: #23282a;
    --marca-texto: #0e1211;

    --pago: #2fa867;
    --pago-tenue: #10241a;
    --pago-linha: #1e4632;

    --vencer: #be8722;
    --vencer-tenue: #251c0c;
    --vencer-linha: #4a3818;

    --atraso: #d64a64;
    --atraso-tenue: #2a1219;
    --atraso-linha: #52222e;

    --neutro: #8a938e;
    --neutro-tenue: #1c2220;
    --neutro-linha: #313a36;

    --marca-grafico: #2fa867;
    --marca-grafico-2: #7d8783;
    --grelha: #232a27;

    --sombra-1: 0 1px 2px rgba(0, 0, 0, 0.4);
    --sombra-2: 0 1px 3px rgba(0, 0, 0, 0.5), 0 4px 12px -4px rgba(0, 0, 0, 0.4);
    --sombra-3: 0 12px 32px -12px rgba(0, 0, 0, 0.8);
}

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    min-height: 100dvh;
    background: var(--fundo);
    color: var(--texto);
    font-family: var(--corpo);
    font-size: 15px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    padding-bottom: env(safe-area-inset-bottom);
}

/* --- Tipografia ---------------------------------------------------------- */

h1,
h2,
h3 {
    margin: 0;
    font-weight: 700;
    letter-spacing: -0.021em;
    line-height: 1.15;
}

h1 {
    font-size: clamp(1.45rem, 4.5vw, 1.8rem);
}
h2 {
    font-size: 1.15rem;
}
h3 {
    font-size: 1rem;
    letter-spacing: -0.012em;
}

p {
    margin: 0 0 var(--e3);
}

a {
    color: var(--marca);
    text-underline-offset: 3px;
}

/* Rótulo pequeno que abre uma secção sem gastar um nível de título. */
.sobrescrito {
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin: 0 0 var(--e3);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--texto-3);
}

.mono,
.num,
.numero__valor,
.tabela td.num {
    font-variant-numeric: tabular-nums;
    font-feature-settings: 'tnum';
}

/* Fora de vista, mas presente para um leitor de ecrã.
   `!important` porque isto é uma utilidade e tem de ganhar sempre. Sem ele,
   `.campo input` — que é mais específica — devolvia a largura de 100% e os 44px
   de altura ao campo de ficheiro escondido da página de criar conta: um bloco
   de 360px posicionado em absoluto com margem negativa, a empurrar a página 15px
   para o lado num telemóvel. */
.so-leitores {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    min-height: 0 !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0 !important;
}

.oculto {
    display: none !important;
}

/* O atributo `hidden` tem de ganhar a qualquer regra de `display`.
   O browser esconde-o com uma regra própria, mas essa perde para qualquer
   folha de estilos — e `.botao { display: inline-flex }` bastava para um
   `botao.hidden = true` não fazer nada. Era o que se passava com o
   "Selecionar todos" da lista de alunos, que aparecia antes de haver seleção,
   e com o filtro de método dos pagamentos, que ficava à vista em "Em falta". */
[hidden] {
    display: none !important;
}

.espaco-cima {
    margin-top: var(--e5);
}
.espaco-baixo {
    margin-bottom: var(--e4);
}
.centrado {
    text-align: center;
}

.entre {
    display: flex;
    align-items: center;
    gap: var(--e3);
    flex-wrap: wrap;
}

/* O que separa os dois lados de uma linha `.entre` é sempre o primeiro filho a
   crescer — quase sempre um `.linha__principal`. Um rótulo em versaletes não
   cresce, e por isso o "Novo plano" ficava colado ao "PLANOS" em vez de ir para
   a direita. Aqui é ele a empurrar. Não se pôs `space-between` na `.entre`
   porque há linhas — os filtros dos pagamentos — que são três campos que devem
   ficar juntos à esquerda, e não espalhados pela largura toda. */
.entre > .sobrescrito {
    margin-right: auto;
}

/* --- Estados ------------------------------------------------------------- */
/* As classes de estado definem `--cor`; todo o resto da folha lê essa variável.
   Trocar um estado é trocar três linhas. */

.e-pago {
    --cor: var(--pago);
    --cor-tenue: var(--pago-tenue);
    --cor-linha: var(--pago-linha);
}
.e-a_vencer {
    --cor: var(--vencer);
    --cor-tenue: var(--vencer-tenue);
    --cor-linha: var(--vencer-linha);
}
.e-atraso,
.e-sem_plano {
    --cor: var(--atraso);
    --cor-tenue: var(--atraso-tenue);
    --cor-linha: var(--atraso-linha);
}
.e-suspenso {
    --cor: var(--neutro);
    --cor-tenue: var(--neutro-tenue);
    --cor-linha: var(--neutro-linha);
}

/* Um texto que toma a cor do estado que lhe puserem ao lado. As classes acima só
   definem a variável — é preciso alguém que a leia. Serve para dizer uma coisa
   dentro de um cartão que está pintado de outra: o seguro por renovar na ficha
   de quem tem a mensalidade em dia. */
.texto-estado {
    color: var(--cor, var(--texto-3));
    font-weight: 600;
}

/* --- Cabeçalho ----------------------------------------------------------- */

.tira {
    position: sticky;
    top: 0;
    z-index: 40;
    display: flex;
    align-items: center;
    justify-content: space-between;
    /* Quebra quando não cabe. A página dos QR Codes tem três botões nesta barra
       e, num telemóvel de 360px, a marca mais os botões passavam 16px da borda —
       o que fazia a página inteira escorregar para o lado. */
    flex-wrap: wrap;
    gap: var(--e3);
    padding: var(--e3) var(--e4);
    background: color-mix(in srgb, var(--superficie) 86%, transparent);
    backdrop-filter: blur(14px) saturate(150%);
    -webkit-backdrop-filter: blur(14px) saturate(150%);
    border-bottom: 1px solid var(--linha);
}

.tira__marca {
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin: 0;
    font-family: var(--display);
    font-size: 0.98rem;
    letter-spacing: 0.055em;
    text-transform: uppercase;
    white-space: nowrap;
}

.tira__marca::before {
    content: '';
    width: 22px;
    height: 22px;
    flex: none;
    border-radius: 50%;
    background: url('/img/pfc.jpg') center / cover no-repeat;
    border: 1px solid var(--linha-forte);
}

.tira__acoes {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    justify-content: flex-end;
    /* Encostados à direita mesmo quando descem para a segunda linha, onde o
       `space-between` da barra já não os empurra. */
    margin-left: auto;
    gap: var(--e2);
}

main {
    /* `width: 100%` não é redundante. O `main` do painel é um item flex dentro
       de `.app__corpo`, e um item flex sem largura declarada dimensiona-se ao
       conteúdo, não ao espaço disponível. Num telemóvel isso dava um `main` de
       472px dentro de um ecrã de 393, e como o `.app__corpo` corta o que passa
       da margem, os 79px de diferença desapareciam sem deixar rasto: o botão
       "Novo aluno" e a coluna das datas ficavam do lado de lá do corte. */
    width: 100%;
    max-width: 1080px;
    margin: 0 auto;
    padding: var(--e5) var(--e4) var(--e8);
}

main.estreito {
    max-width: 430px;
}

section + section {
    margin-top: var(--e6);
}

/* --- Cartões ------------------------------------------------------------- */

.cartao {
    position: relative;
    padding: var(--e4);
    background: var(--superficie);
    border: 1px solid var(--linha);
    border-radius: var(--raio);
    box-shadow: var(--sombra-1);
}

/* Fio de cor no topo, na cor do estado. */
.canto {
    border-color: var(--cor-linha, var(--linha));
}

.canto::before {
    content: '';
    position: absolute;
    inset: -1px -1px auto -1px;
    height: 3px;
    border-radius: var(--raio) var(--raio) 0 0;
    background: var(--cor, var(--linha-forte));
}

/* --- Etiquetas ----------------------------------------------------------- */

.etiqueta {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px 3px 8px;
    border-radius: 999px;
    background: var(--cor-tenue, var(--superficie-2));
    color: var(--cor, var(--texto-2));
    border: 1px solid var(--cor-linha, var(--linha));
    font-size: 0.73rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    white-space: nowrap;
}

.etiqueta::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    flex: none;
}

.etiqueta--vivo::before {
    animation: pulsar-ponto 2s var(--entrada-saida) infinite;
}

@keyframes pulsar-ponto {
    0%,
    100% {
        opacity: 1;
    }
    50% {
        opacity: 0.35;
    }
}

/* --- Botões -------------------------------------------------------------- */

.botao {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--e2);
    padding: 10px 18px;
    min-height: 42px;
    border: 1px solid transparent;
    border-radius: var(--raio-p);
    background: var(--marca);
    color: var(--marca-texto);
    font-family: inherit;
    font-size: 0.9rem;
    font-weight: 600;
    letter-spacing: -0.005em;
    text-decoration: none;
    /* Um botão encolhe até ao seu conteúdo e depois pára. Sem isto, "Check-in"
       partia-se em "Check-" e "in" na barra de um telemóvel de 360px em vez de
       a barra quebrar, que é o que se quer. */
    white-space: nowrap;
    cursor: pointer;
    box-shadow: var(--sombra-1);
    transition:
        transform 140ms var(--saida),
        background-color 140ms ease,
        border-color 140ms ease,
        box-shadow 140ms ease;
}

.botao:active {
    transform: scale(0.97);
    transition-duration: 90ms;
}

@media (hover: hover) and (pointer: fine) {
    .botao:hover {
        background: var(--marca-2);
    }
}

.botao--linha {
    background: var(--superficie);
    color: var(--texto);
    border-color: var(--linha-forte);
}

@media (hover: hover) and (pointer: fine) {
    .botao--linha:hover {
        background: var(--superficie-2);
        border-color: var(--texto-3);
    }
}

/* Um botão que representa uma escolha em vigor fica preenchido, como o
   segmento escolhido. Sem isto, o filtro ativo — "Todos", ao abrir a lista —
   parecia tão por escolher como os outros, e não havia forma de saber o que
   estava a ser mostrado. */
.botao--linha[aria-pressed='true'] {
    background: var(--marca);
    color: var(--marca-texto);
    border-color: var(--marca);
}

@media (hover: hover) and (pointer: fine) {
    .botao--linha[aria-pressed='true']:hover {
        background: var(--marca-2);
        border-color: var(--marca-2);
    }
}

.botao--perigo {
    background: var(--atraso);
    color: #fff;
}

/* O verde deixou de ser a cor da marca; onde uma ação é mesmo de "confirmar
   que está em dia", pede-se explicitamente. */
.botao--ok {
    background: var(--pago);
    color: #fff;
}

.botao--pequeno {
    padding: 6px 12px;
    min-height: 34px;
    font-size: 0.82rem;
}

.botao--largo {
    width: 100%;
    min-height: 48px;
}

.botao[disabled] {
    opacity: 0.45;
    cursor: not-allowed;
    transform: none;
}

:focus-visible {
    outline: 2px solid var(--marca);
    outline-offset: 2px;
    border-radius: 4px;
}

/* --- Formulários --------------------------------------------------------- */

.campo {
    margin-bottom: var(--e4);
}

.campo > label {
    display: block;
    margin-bottom: 6px;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--texto-2);
}

.campo input,
.campo select,
.campo textarea {
    width: 100%;
    padding: 10px 12px;
    /* 16px impede o iOS de dar zoom ao focar o campo. */
    font-size: 16px;
    font-family: inherit;
    color: var(--texto);
    background: var(--superficie);
    border: 1px solid var(--linha-forte);
    border-radius: var(--raio-p);
    min-height: 44px;
    transition:
        border-color 140ms ease,
        box-shadow 140ms ease;
}

.campo input::placeholder,
.campo textarea::placeholder {
    color: var(--texto-3);
}

.campo input:focus,
.campo select:focus,
.campo textarea:focus {
    outline: none;
    border-color: var(--marca);
    box-shadow: 0 0 0 3px var(--marca-tenue);
}

.campo textarea {
    min-height: 84px;
    resize: vertical;
}

/* Só os campos de PIN: são seis caixas a fingir de uma. O seletor tem de incluir
   o `type='password'` — enquanto apanhava qualquer `inputmode='numeric'`, o
   código postal e o NIF apareciam com o mesmo aspeto de segredo. */
.campo input[type='password'][inputmode='numeric'] {
    font-size: 1.4rem;
    font-weight: 600;
    letter-spacing: 0.5em;
    text-indent: 0.5em;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.campo__dica {
    display: block;
    margin-top: 5px;
    font-size: 0.79rem;
    color: var(--texto-3);
}

/* A mesma classe serve para duas coisas: a dica por baixo do campo, que é uma
   linha própria, e o "(opcional)" dentro do rótulo, que é parte da frase. Em
   bloco, o "(opcional)" caía para debaixo de "Email" e dava a impressão de
   serem dois rótulos. */
.campo > label .campo__dica {
    display: inline;
    margin-top: 0;
}

.campo input[type='file'] {
    padding: 9px;
    font-size: 0.84rem;
    color: var(--texto-2);
}

/* --- Escolher fotografia -------------------------------------------------- */
/* O `input[type=file]` cru mostra "Nenhum ficheiro escolhido" e um botão do
   sistema — não parece um campo obrigatório, e em telemóvel é minúsculo. Aqui
   o input fica escondido e o que se toca é o rótulo. */

.foto {
    display: flex;
    align-items: center;
    gap: var(--e4);
}

.foto__alvo {
    position: relative;
    width: 76px;
    height: 76px;
    flex: none;
    border-radius: 18px;
    background: var(--superficie-2);
    border: 1px dashed var(--linha-forte);
    background-size: cover;
    background-position: center;
    transition:
        border-color 160ms ease,
        transform 200ms var(--saida);
}

/* Silhueta enquanto não há foto: diz o que se espera ali sem uma palavra. */
.foto__alvo::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background:
        radial-gradient(circle at 50% 36%, var(--texto-3) 0 13px, transparent 13.5px),
        radial-gradient(ellipse at 50% 92%, var(--texto-3) 0 22px, transparent 22.5px);
    opacity: 0.28;
    transition: opacity 160ms ease;
}

.foto__alvo--cheio {
    border-style: solid;
    border-color: var(--pago);
}

.foto__alvo--cheio::after {
    opacity: 0;
}

.foto__texto {
    flex: 1;
    min-width: 0;
}

.foto__texto .campo__dica {
    margin-top: var(--e2);
}

/* Em falta: só depois de a pessoa tentar submeter. Marcar a vermelho um campo
   que ainda não teve hipótese de ser preenchido é ralhar antes do erro. */
.campo--erro input,
.campo--erro select,
.campo--erro textarea {
    border-color: var(--atraso);
}

.campo--erro > label {
    color: var(--atraso);
}

/* A explicação vive ao pé do campo, não num aviso no topo da página.
   Enquanto o formulário tinha nove campos o aviso lá em cima via-se; com
   dezasseis, falhar no NIF deixava a frase a mil e quatrocentos píxeis de
   distância e a pessoa via uma caixa vermelha sem saber porquê. */
.campo__erro {
    display: block;
    margin-top: 5px;
    font-size: 0.79rem;
    font-weight: 500;
    color: var(--atraso);
}

.campo--erro .foto__alvo {
    border-color: var(--atraso);
    border-style: solid;
}

.campo--erro .foto__alvo::after {
    background:
        radial-gradient(circle at 50% 36%, var(--atraso) 0 13px, transparent 13.5px),
        radial-gradient(ellipse at 50% 92%, var(--atraso) 0 22px, transparent 22.5px);
    opacity: 0.4;
}

/* --- Grupos de campos ----------------------------------------------------- */

/* Treze campos numa coluna de 430px são uma escada sem patamares. `fieldset` e
   não `div` porque é o agrupamento que um leitor de ecrã anuncia; o resto do
   bloco é só a tirar a moldura que o browser lhe põe. */
.grupo {
    margin: 0 0 var(--e6);
    padding: 0;
    border: 0;
    /* Sem isto um fieldset recusa encolher abaixo do conteúdo, e o textarea
       arrasta a página para o lado no telemóvel. */
    min-inline-size: 0;
}

/* O último grupo não empurra o botão "Criar conta" para longe: 32px depois do
   PIN faziam o botão parecer desligado do formulário. */
.grupo:last-of-type {
    margin-bottom: 0;
}

/* Um `<legend>` ignora `display: flex` em vários browsers, e por isso não se
   reaproveita aqui a `.sobrescrito`, que é flex. */
.grupo__titulo {
    display: block;
    /* Um `<legend>` encolhe ao conteúdo mesmo em `block` — sem isto, nada se lhe
       consegue alinhar à direita. */
    width: 100%;
    padding: 0;
    margin: 0 0 var(--e3);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--texto-3);
}

/* A caixa de escolha foge à regra dos 100% de largura que vale para os outros
   controlos, mas não à dos 44px: é o único campo do formulário que se preenche
   com um toque, e é o que o resto da aplicação garante. */
.campo--escolha {
    display: flex;
    align-items: center;
    min-height: 44px;
    /* Sem `gap`: o espaço entre a caixa e o texto é padding do próprio rótulo.
       Como `gap`, aqueles 12px não pertenciam a nenhum dos dois e eram uma
       faixa morta no meio do alvo. */
}

.campo--escolha input[type='checkbox'] {
    width: 22px;
    height: 22px;
    min-height: 0;
    flex: none;
    accent-color: var(--marca);
}

/* `flex: 1` e altura toda: o alvo é a linha inteira, não as duas palavras. */
.campo--escolha > label {
    flex: 1;
    display: flex;
    align-items: center;
    min-height: 44px;
    margin: 0;
    padding-left: var(--e3);
    font-size: 0.9rem;
    font-weight: 500;
    color: var(--texto);
    cursor: pointer;
}

/* Tem de vir depois da regra acima: com a mesma especificidade e escrita antes,
   o vermelho do erro perdia para a cor normal do rótulo. */
.campo--erro.campo--escolha > label {
    color: var(--atraso);
}

/* --- Quem está a entrar --------------------------------------------------- */

.quem {
    display: flex;
    align-items: center;
    gap: var(--e3);
    padding: var(--e3);
    margin-bottom: var(--e5);
    background: var(--superficie-2);
    border: 1px solid var(--linha);
    border-radius: var(--raio);
}

.quem__retrato {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    flex: none;
    border-radius: 11px;
    background: var(--marca);
    color: var(--marca-texto);
    font-family: var(--display);
    font-size: 0.95rem;
    letter-spacing: 0.04em;
}

.quem__texto {
    flex: 1;
    min-width: 0;
}

.quem__nome {
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.quem__id {
    font-size: 0.84rem;
    color: var(--texto-3);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* --- Avisos -------------------------------------------------------------- */

.aviso {
    display: flex;
    gap: var(--e2);
    padding: var(--e3) var(--e4);
    margin-bottom: var(--e4);
    border-radius: var(--raio-p);
    background: var(--cor-tenue, var(--superficie-2));
    border: 1px solid var(--cor-linha, var(--linha));
    color: var(--cor, var(--texto));
    font-size: 0.89rem;
    animation: aviso-entra 220ms var(--saida) both;
}

@keyframes aviso-entra {
    from {
        opacity: 0;
        transform: translateY(-5px);
    }
}

.aviso--erro {
    --cor: var(--atraso);
    --cor-tenue: var(--atraso-tenue);
    --cor-linha: var(--atraso-linha);
}

.aviso--ok {
    --cor: var(--pago);
    --cor-tenue: var(--pago-tenue);
    --cor-linha: var(--pago-linha);
}

/* --- Listas -------------------------------------------------------------- */

.lista {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    /* A outra metade do mesmo problema. Uma grelha sem colunas declaradas cria
       uma coluna `auto`, e uma coluna `auto` cresce até ao conteúdo mais largo
       que tiver — aqui, o nome mais comprido mais a bandeira mais a data, 440px.
       `minmax(0, 1fr)` diz que a coluna é uma fração do que há, e nunca mais do
       que isso; a partir daí é o nome que trunca com reticências, como sempre
       esteve preparado para fazer. */
    grid-template-columns: minmax(0, 1fr);
    gap: 6px;
}

.linha {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--e3);
    width: 100%;
    padding: var(--e3);
    text-align: left;
    font: inherit;
    color: inherit;
    background: var(--superficie);
    border: 1px solid var(--linha);
    border-radius: var(--raio-p);
    cursor: pointer;
    transition:
        transform 160ms var(--saida),
        border-color 160ms ease,
        background-color 160ms ease;
}

/* Traço de estado à esquerda, curto — lê-se ao percorrer a lista sem pesar
   como uma barra inteira. */
.linha::before {
    content: '';
    position: absolute;
    left: 0;
    top: 50%;
    width: 3px;
    height: 0;
    border-radius: 0 3px 3px 0;
    background: var(--cor, transparent);
    transform: translateY(-50%);
    transition: height 180ms var(--saida);
}

.linha[class*='e-']::before {
    height: 44%;
}

@media (hover: hover) and (pointer: fine) {
    .linha:hover {
        background: var(--superficie-2);
        border-color: var(--linha-forte);
    }
    .linha:hover::before {
        height: 68%;
    }
}

.linha:active {
    transform: scale(0.995);
    transition-duration: 90ms;
}

.linha__principal {
    flex: 1;
    min-width: 0;
}

.linha__nome {
    font-weight: 600;
    letter-spacing: -0.008em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.linha__meta {
    font-size: 0.82rem;
    color: var(--texto-3);
}

/* Bandeira ao lado do nome: a resposta binária que a lista de alunos existe
   para dar. Fica na mesma linha do nome, e não no fim da linha, porque o olho
   percorre a coluna dos nomes — no fim passaria despercebida. */
.bandeira {
    display: inline-block;
    flex: none;
    padding: 1px 7px;
    border-radius: 999px;
    background: var(--cor-tenue);
    color: var(--cor);
    border: 1px solid var(--cor-linha);
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    vertical-align: 1px;
    white-space: nowrap;
}

/* Uma linha "rica" leva mais do que cabe de lado num telemóvel: avatar, nome,
   um par de datas e ainda um botão. Sem isto era cortada — o corpo do painel
   corta o que transborde para os lados, para a barra de navegação não fugir.
   Aqui parte-se em duas alturas, que é o que se quer.

   O `wrap` fica ligado em todas as larguras: numa janela estreita de portátil
   o problema é o mesmo, e onde há espaço nada quebra. */
.linha--rica {
    flex-wrap: wrap;
    row-gap: var(--e2);
}

@media (max-width: 767px) {
    /* O avatar e o nome ficam na primeira altura; as datas e o botão descem. */
    .linha--rica .linha__principal {
        flex: 1 1 55%;
    }

    .linha--rica .linha__fim {
        flex: 1 1 auto;
        text-align: left;
    }

    /* Sem isto o botão encolhia e espremia o próprio texto em vez de descer. */
    .linha--rica .botao {
        flex: none;
        margin-left: auto;
    }
}

/* Com bandeira, a linha vira flex e é o nome que trunca — a bandeira nunca. */
.linha__nome--com-bandeira {
    display: flex;
    align-items: center;
    gap: var(--e2);
    min-width: 0;
    white-space: normal;
}

.linha__nome-texto {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.linha__fim {
    flex: none;
    text-align: right;
    font-size: 0.84rem;
    color: var(--texto-2);
    font-variant-numeric: tabular-nums;
}

/* Um número a fechar uma linha. Não é um tile: com o tamanho de tile ficaria
   maior do que o nome do aluno ao lado, e a hierarquia invertia-se. */
.linha__numero {
    font-size: 1.3rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.1;
    color: var(--cor, var(--texto));
    font-variant-numeric: tabular-nums;
}

.vazio {
    padding: var(--e7) var(--e4);
    text-align: center;
    color: var(--texto-3);
    background: var(--superficie);
    border: 1px dashed var(--linha-forte);
    border-radius: var(--raio);
}

/* --- Retrato ------------------------------------------------------------- */

.retrato {
    width: 40px;
    height: 40px;
    flex: none;
    border-radius: 11px;
    object-fit: cover;
    background: var(--superficie-3);
    border: 1px solid var(--linha);
}

.retrato--grande {
    width: 72px;
    height: 72px;
    border-radius: 16px;
}

.retrato--iniciais {
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--display);
    font-size: 0.95rem;
    letter-spacing: 0.04em;
    color: var(--texto-2);
    background: var(--superficie-2);
}

.retrato--grande.retrato--iniciais {
    font-size: 1.6rem;
}

/* ===========================================================================
   Painel — os blocos que fazem dele um painel
   =========================================================================== */

/* Cabeçalho de página: título, contexto e ações no mesmo eixo. */
.pagina {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--e4);
    flex-wrap: wrap;
    margin-bottom: var(--e5);
}

.pagina__contexto {
    margin: 2px 0 0;
    font-size: 0.88rem;
    color: var(--texto-3);
}

.pagina__acoes {
    display: flex;
    gap: var(--e2);
    flex-wrap: wrap;
}

/* --- Tiles de indicador --------------------------------------------------- */
/* Compactos de propósito. Números gigantes num painel enchem o ecrã e obrigam
   a percorrer duas vezes para ver seis valores; o que se quer é ler os seis de
   uma vez e parar só no que estiver fora do normal. */

.tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
    gap: var(--e2);
}

.tile {
    position: relative;
    padding: var(--e4);
    background: var(--superficie);
    border: 1px solid var(--linha);
    border-radius: var(--raio);
    box-shadow: var(--sombra-1);
}

.tile__rotulo {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0 0 var(--e2);
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--texto-3);
}

/* O ponto só aparece nos indicadores que exigem uma decisão. Um ponto em todos
   deixaria de significar coisa nenhuma. */
.tile__rotulo::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--cor);
    flex: none;
    display: none;
}

.tile[class*='e-'] .tile__rotulo::before {
    display: block;
}

.tile__valor {
    font-size: 1.85rem;
    font-weight: 700;
    letter-spacing: -0.03em;
    line-height: 1.05;
    font-variant-numeric: tabular-nums;
    color: var(--cor, var(--texto));
}

.tile__nota {
    margin: 4px 0 0;
    font-size: 0.8rem;
    color: var(--texto-3);
}

/* --- Gráficos ------------------------------------------------------------ */

.grafico {
    padding: var(--e4);
    background: var(--superficie);
    border: 1px solid var(--linha);
    border-radius: var(--raio);
    box-shadow: var(--sombra-1);
}

.grafico__topo {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--e3);
    margin-bottom: var(--e4);
    flex-wrap: wrap;
}

.grafico__titulo {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 650;
    letter-spacing: -0.01em;
}

.grafico__resumo {
    font-size: 0.82rem;
    color: var(--texto-3);
    font-variant-numeric: tabular-nums;
}

.grafico__tela {
    position: relative;
    width: 100%;
}

.grafico__tela svg {
    display: block;
    width: 100%;
    /* 100% e não `auto`: o SVG é desenhado à largura real do contentor, com a
       `viewBox` a coincidir com os pixéis do ecrã. Com `auto`, meio pixel de
       arredondamento entre a medição e o desenho deixava um fio branco em
       baixo. */
    height: 100%;
    overflow: visible;
}

/* Grelha e eixos: fios de cabelo, sempre sólidos. Tracejado acrescenta ruído e
   lê-se como "projeção" quando é só uma grelha. */
.g-grelha {
    stroke: var(--grelha);
    stroke-width: 1;
}

.g-eixo {
    fill: var(--texto-3);
    font-size: 10.5px;
    font-family: var(--corpo);
    font-variant-numeric: tabular-nums;
}

.g-barra {
    fill: var(--marca-grafico);
    transition: opacity 120ms ease;
}

.g-barra--neutra {
    fill: var(--marca-grafico-2);
}

/* Alvo de rato maior do que a barra: uma barra de 6px seria impossível de
   apanhar com o dedo. */
.g-alvo {
    fill: transparent;
    cursor: pointer;
}

.g-alvo:hover + .g-barra,
.g-alvo:focus-visible + .g-barra {
    opacity: 0.62;
}

.g-vazio {
    fill: var(--linha);
}

.g-dica {
    position: absolute;
    z-index: 5;
    padding: 7px 10px;
    background: var(--texto);
    color: var(--superficie);
    border-radius: 7px;
    font-size: 0.78rem;
    line-height: 1.4;
    white-space: nowrap;
    pointer-events: none;
    box-shadow: var(--sombra-2);
    transform: translate(-50%, -100%);
    opacity: 0;
    transition: opacity 110ms ease;
}

.g-dica--visivel {
    opacity: 1;
}

.g-dica b {
    font-variant-numeric: tabular-nums;
}

/* --- Duas colunas --------------------------------------------------------- */

.duplo {
    display: grid;
    gap: var(--e5);
    align-items: start;
}

/* Os gráficos de evolução do painel: um por linha, sempre. São três leituras do
   mesmo período — quem apareceu, quantos pagavam, quanto entrou — e só se leem
   umas contra as outras se partilharem a largura e a escala do tempo. */
.graficos {
    display: grid;
    gap: var(--e5);
}

@media (min-width: 900px) {
    .duplo {
        grid-template-columns: 1fr 1fr;
    }

    .duplo--largo {
        grid-template-columns: 1.35fr 1fr;
    }
}

/* --- Tabela -------------------------------------------------------------- */

.tabela {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.87rem;
}

.tabela th {
    padding: var(--e2) var(--e3);
    text-align: left;
    font-size: 0.71rem;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--texto-3);
    border-bottom: 1px solid var(--linha-forte);
    white-space: nowrap;
}

.tabela td {
    padding: var(--e3);
    border-bottom: 1px solid var(--linha);
}

.tabela tbody tr:last-child td {
    border-bottom: 0;
}

.tabela tbody tr {
    transition: background-color 120ms ease;
}

@media (hover: hover) and (pointer: fine) {
    .tabela tbody tr:hover {
        background: var(--superficie-2);
    }
}

.tabela td.num {
    text-align: right;
    white-space: nowrap;
}

/* O nome do aluno leva à ficha dele. O link enche a célula em vez de ser só o
   texto: num iPad, acertar com o dedo numa linha de 16px de altura é sorte. */
.tabela td a {
    display: block;
    padding: var(--e3) 0;
    margin: calc(-1 * var(--e3)) 0;
}

.rolavel {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    background: var(--superficie);
    border: 1px solid var(--linha);
    border-radius: var(--raio);
    box-shadow: var(--sombra-1);
}

.rolavel .tabela {
    min-width: 560px;
}

/* --- Diálogo ------------------------------------------------------------- */

dialog {
    width: min(430px, calc(100vw - var(--e5)));
    max-height: 88dvh;
    overflow-y: auto;
    padding: var(--e5);
    color: var(--texto);
    background: var(--superficie);
    border: 1px solid var(--linha);
    border-radius: var(--raio-g);
    box-shadow: var(--sombra-3);
}

/* Um modal não está preso a nenhum gatilho: cresce do centro. */
dialog[open] {
    animation: dialogo-entra 200ms var(--saida);
}

@keyframes dialogo-entra {
    from {
        opacity: 0;
        /* Nunca de `scale(0)`: nada no mundo real aparece do nada. */
        transform: scale(0.97) translateY(6px);
    }
}

dialog::backdrop {
    background: rgba(16, 20, 19, 0.42);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    animation: fundo-entra 200ms ease;
}

@keyframes fundo-entra {
    from {
        opacity: 0;
    }
}

dialog h2 {
    margin-bottom: var(--e4);
}

/* O título leva o foco ao abrir (ver dialogo.js), e o Chrome desenha-lhe o anel
   à volta. Aqui o anel não diz nada a ninguém: não é um controlo, não se carrega
   nele, e quem navega por teclado continua a ver o anel no primeiro campo assim
   que carregar em Tab. */
#dialogo-titulo:focus,
.menu__cabecalho:focus {
    outline: none;
}

/* A linha das ações cola-se ao fundo do diálogo.
   Sem isto, num iPhone SE o formulário das aulas media 639px dentro de um
   diálogo de 587, e o que ficava abaixo do corte era o "Guardar" — enquanto o
   "Apagar aula", em vermelho, ficava à vista. A ação principal escondida e a
   destrutiva em destaque é exatamente ao contrário do que devia ser.
   As margens negativas levam a faixa até às bordas do diálogo, para o fundo
   tapar o que passa por baixo dela em vez de o deixar espreitar. */
.dialogo__fim {
    position: sticky;
    bottom: calc(-1 * var(--e5));
    z-index: 1;
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin: var(--e5) calc(-1 * var(--e5)) calc(-1 * var(--e5));
    padding: var(--e4) var(--e5) var(--e5);
    flex-wrap: wrap;
    background: var(--superficie);
    border-top: 1px solid var(--linha);
}

/* Empurra o Cancelar/Guardar para a direita e deixa o "Apagar" sozinho do
   outro lado — longe do polegar que ia carregar em Guardar. */
.dialogo__espaco {
    flex: 1;
}

/* Num telemóvel os três botões não cabem lado a lado, e a quebra deixava o
   "Apagar aula" em cima, vermelho e à cabeça, com o "Guardar" a escorregar
   para uma segunda linha por baixo dele. Empilhados, cada um ocupa a largura
   toda e é preciso apontar; `column-reverse` inverte a ordem do HTML — apagar,
   cancelar, guardar — e põe o Guardar encostado ao formulário, onde o polegar
   já está, com o Apagar no extremo oposto. */
@media (max-width: 480px) {
    .dialogo__fim {
        flex-direction: column-reverse;
        align-items: stretch;
        gap: var(--e2);
    }

    .dialogo__espaco {
        display: none;
    }

    .dialogo__fim .botao {
        width: 100%;
    }

    /* Empilhado e à largura toda, o vermelho cheio passava a ser a coisa mais
       chamativa do ecrã — num formulário que existe para editar, não para
       apagar. Vazio, continua a ser inequivocamente o botão de apagar e deixa
       de disputar o olho com o "Guardar". */
    .dialogo__fim .botao--perigo {
        background: none;
        color: var(--atraso);
        border: 1px solid var(--atraso);
    }
}

/* ===========================================================================
   Entradas e cascatas
   =========================================================================== */

.entra {
    animation: subir 380ms var(--saida) both;
}

@keyframes subir {
    from {
        opacity: 0;
        transform: translateY(10px);
    }
}

/* Cascata curta de propósito: atrasos longos fazem a interface parecer lenta
   em vez de viva. O atraso vem de `--i`, posto pelo JS. */
.cascata > * {
    animation: subir 340ms var(--saida) both;
    animation-delay: calc(var(--i, 0) * 40ms);
}

.contador {
    display: inline-block;
    font-variant-numeric: tabular-nums;
}

/* --- Esqueleto ----------------------------------------------------------- */

.esqueleto {
    position: relative;
    overflow: hidden;
    background: var(--superficie);
    border: 1px solid var(--linha);
    border-radius: var(--raio-p);
}

.esqueleto::after {
    content: '';
    position: absolute;
    inset: 0;
    transform: translateX(-100%);
    background: linear-gradient(90deg, transparent, var(--superficie-2), transparent);
    animation: brilho 1.4s infinite;
}

@keyframes brilho {
    to {
        transform: translateX(100%);
    }
}

.esqueleto--linha {
    height: 62px;
}

.esqueleto--numero {
    height: 98px;
    border-radius: var(--raio);
}

.pulsar {
    padding: var(--e7);
    text-align: center;
    color: var(--texto-3);
    font-size: 0.88rem;
}

/* ===========================================================================
   Check-in — o ecrã que tem de ser lido de relance
   =========================================================================== */

.checkin {
    position: relative;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--e5);
    padding: var(--e5) var(--e4);
    text-align: center;
    max-width: 470px;
    margin: 0 auto;
}

.checkin__marca {
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin: 0;
    font-family: var(--display);
    font-size: 0.8rem;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--texto-3);
}

.checkin__marca::before {
    content: '';
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: url('/img/pfc.jpg') center / cover no-repeat;
    border: 1px solid var(--linha-forte);
}

/* --- O disco ------------------------------------------------------------- */

.disco {
    position: relative;
    width: min(224px, 60vw);
    aspect-ratio: 1;
    display: grid;
    place-items: center;
}

/* Halo que se expande uma vez. No tema claro fica muito mais discreto: sobre
   branco, um brilho forte lê-se como borrão em vez de luz. */
.disco::before {
    content: '';
    position: absolute;
    inset: 8%;
    border-radius: 50%;
    background: var(--cor-tenue, var(--pago-tenue));
    opacity: 0;
}

.disco--ativo::before {
    animation: onda 800ms var(--saida) both;
}

@keyframes onda {
    0% {
        opacity: 0;
        transform: scale(0.7);
    }
    100% {
        opacity: 1;
        transform: scale(1);
    }
}

.disco__anel {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    transform: rotate(-90deg);
}

.disco__trilho {
    fill: none;
    stroke: var(--superficie-3);
    stroke-width: 6;
}

/* O arco desenha-se: é o gesto que dá a sensação de que o sistema *verificou*
   alguma coisa, em vez de ter simplesmente aparecido um visto. */
.disco__arco {
    fill: none;
    stroke: var(--cor, var(--pago));
    stroke-width: 6;
    stroke-linecap: round;
    stroke-dasharray: 302;
    stroke-dashoffset: 302;
}

.disco--ativo .disco__arco {
    animation: desenhar-anel 720ms var(--saida) 60ms both;
}

@keyframes desenhar-anel {
    to {
        stroke-dashoffset: 0;
    }
}

/* Enquanto espera, o disco roda. Diz "estou a trabalhar" sem um spinner, que
   neste ecrã pareceria um erro à espera de acontecer. */
.disco:not(.disco--ativo) .disco__arco {
    stroke-dasharray: 62 240;
    stroke-dashoffset: 0;
    stroke: var(--texto-3);
}

.disco:not(.disco--ativo) .disco__anel {
    transform-origin: center;
    animation: aguardar 1s linear infinite;
}

@keyframes aguardar {
    from {
        transform: rotate(-90deg);
    }
    to {
        transform: rotate(270deg);
    }
}

.disco__marca {
    position: relative;
    width: 42%;
    height: 42%;
    color: var(--cor, var(--pago));
}

.disco__marca path {
    fill: none;
    stroke: currentColor;
    stroke-width: 7;
    stroke-linecap: round;
    stroke-linejoin: round;
    stroke-dasharray: 100;
    stroke-dashoffset: 100;
}

.disco--ativo .disco__marca path {
    animation: desenhar-marca 400ms var(--saida) 400ms both;
}

@keyframes desenhar-marca {
    to {
        stroke-dashoffset: 0;
    }
}

/* --- Texto do resultado -------------------------------------------------- */

.checkin__veredicto {
    margin: 0;
    font-family: var(--display);
    font-size: clamp(2.2rem, 10vw, 3rem);
    line-height: 0.96;
    text-transform: uppercase;
    letter-spacing: 0.004em;
    color: var(--texto);
}

.checkin__nome {
    margin: 0;
    font-size: 1.18rem;
    font-weight: 650;
    letter-spacing: -0.015em;
}

.checkin__hora {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--e3);
    margin: 0;
    font-size: 0.93rem;
    color: var(--texto-3);
    font-variant-numeric: tabular-nums;
}

.checkin__hora span:first-child {
    font-family: var(--display);
    font-size: 1.45rem;
    color: var(--texto);
    letter-spacing: 0.01em;
}

.checkin__estado {
    display: inline-flex;
    align-items: center;
    gap: var(--e2);
    padding: 10px 18px;
    border-radius: 999px;
    background: var(--cor-tenue, var(--pago-tenue));
    border: 1px solid var(--cor-linha, var(--linha));
    color: var(--cor, var(--pago));
    font-size: 0.93rem;
    font-weight: 600;
}

.checkin__estado::before {
    content: '';
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
    flex: none;
}

.checkin__rodape {
    margin: 0;
    font-size: 0.86rem;
    color: var(--texto-3);
    max-width: 30ch;
}

/* ===========================================================================
   Página inicial
   =========================================================================== */

.entrada {
    position: relative;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    max-width: 430px;
    margin: 0 auto;
    padding: var(--e7) var(--e4);
}

.entrada__titulo {
    margin: 0 0 var(--e4);
    font-family: var(--display);
    font-size: clamp(2.9rem, 15vw, 4.1rem);
    line-height: 0.88;
    text-transform: uppercase;
    letter-spacing: -0.005em;
    animation: subir 520ms var(--saida) both;
}

.entrada__titulo em {
    font-style: normal;
    color: var(--marca);
}

.entrada__regua {
    height: 3px;
    width: 78px;
    border-radius: 2px;
    background: var(--marca);
    margin-bottom: var(--e5);
    animation: regua 620ms var(--saida) 120ms both;
}

@keyframes regua {
    from {
        width: 0;
        opacity: 0;
    }
}

.entrada__lema {
    color: var(--texto-2);
    margin-bottom: var(--e6);
    font-size: 1rem;
    animation: subir 520ms var(--saida) 200ms both;
}

.entrada__acoes {
    display: grid;
    gap: var(--e3);
}

.entrada__acoes > * {
    animation: subir 460ms var(--saida) both;
}
.entrada__acoes > *:nth-child(1) {
    animation-delay: 280ms;
}
.entrada__acoes > *:nth-child(2) {
    animation-delay: 340ms;
}
.entrada__acoes > *:nth-child(3) {
    animation-delay: 400ms;
}

.entrada__acoes .botao:first-child {
    min-height: 58px;
    font-size: 1.02rem;
}

.entrada__info {
    margin-top: var(--e7);
    padding-top: var(--e4);
    border-top: 1px solid var(--linha);
    font-size: 0.86rem;
    color: var(--texto-3);
    animation: subir 460ms var(--saida) 460ms both;
}

/* ===========================================================================
   QR Codes para imprimir
   =========================================================================== */

.folha {
    background: #fff;
    color: #000;
    border: 1px solid var(--linha);
    border-radius: var(--raio);
    padding: var(--e7) var(--e5);
    text-align: center;
    margin-bottom: var(--e5);
}

.folha__titulo {
    margin: 0;
    font-family: var(--display);
    font-size: 2.6rem;
    text-transform: uppercase;
}

.folha__legenda {
    margin: var(--e1) 0 var(--e5);
    font-size: 1.08rem;
    color: #333;
}

.folha .sobrescrito {
    justify-content: center;
    color: #666;
}

.folha__qr {
    display: block;
    width: min(320px, 70vw);
    height: auto;
    margin: 0 auto;
}

.folha__url {
    margin-top: var(--e4);
    font-size: 0.8rem;
    word-break: break-all;
    color: #666;
    font-variant-numeric: tabular-nums;
}

@media print {
    .tira,
    .abas,
    .nao-imprimir {
        display: none !important;
    }

    body {
        background: #fff;
    }

    main {
        padding: 0;
        max-width: none;
    }

    .folha {
        border: 0;
        page-break-after: always;
        display: flex;
        flex-direction: column;
        justify-content: center;
        min-height: 96vh;
        margin: 0;
    }

    .folha__qr {
        width: 68%;
    }
}

/* ===========================================================================
   Ecrãs maiores
   =========================================================================== */

@media (min-width: 720px) {
    body {
        font-size: 15.5px;
    }

    main {
        padding: var(--e6) var(--e5) var(--e8);
    }

    .colunas {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: var(--e5);
        align-items: start;
    }

    /* A ficha de inscrição são dezasseis campos. Numa coluna de 430px isso é
       uma fita de dois metros e meio ao centro de um ecrã vazio; aqui a coluna
       alarga e os campos que se leem aos pares — código postal e localidade,
       C.C. e NIF — ficam lado a lado. No telemóvel nada disto se aplica e o
       formulário continua exatamente como estava. */
    main.estreito.ficha {
        max-width: 560px;
    }

    /* O `gap` da `.colunas` é vertical de mais para campos de formulário, que já
       trazem a sua margem. */
    .grupo.colunas {
        row-gap: 0;
        column-gap: var(--e4);
    }

    /* O `<legend>` e os campos que precisam da linha toda — a morada não cabe
       em meia. */
    .grupo.colunas > .grupo__titulo,
    .grupo.colunas > .campo--largo {
        grid-column: 1 / -1;
    }

    .tile__valor {
        font-size: 2.05rem;
    }
}

/* ===========================================================================
   A moldura do painel
   ---------------------------------------------------------------------------
   Preta em qualquer tema, porque é a identidade do ginásio e não uma
   preferência de leitura. O conteúdo ao lado é que segue o tema.

   Uma navegação só, em três formas. No telemóvel vai para baixo — é a única
   zona que o polegar alcança sem malabarismo com o telemóvel numa mão. No iPad
   em pé fica ao lado, só com ícones. No iPad deitado e no portátil, ícones com
   texto. São cinco secções, por isso não há hambúrguer nenhum: um menu
   escondido custa sempre um toque a mais.
   =========================================================================== */

.app {
    /* Sem o `padding-bottom` da regra geral: aqui quem trata da barra de gestos
       é a própria barra de navegação. */
    padding-bottom: 0;
}

.app__corpo {
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    /* Nada aqui dentro pode alargar a página para os lados. Quando isso
       acontecia — a tabela de pagamentos com 560px num telemóvel de 380 — a
       barra de navegação fixa deixava de acompanhar o ecrã e fugia.
       `clip` e não `hidden`: `hidden` criaria um contentor de scroll e partia o
       `position: sticky` do topo. */
    overflow-x: clip;
}

/* --- A barra ------------------------------------------------------------- */

.lateral {
    position: fixed;
    z-index: 60;
    display: flex;
    background: var(--moldura);
    color: var(--moldura-texto);
}

/* --- Marca --------------------------------------------------------------- */

.lateral__marca {
    display: flex;
    align-items: center;
    gap: var(--e3);
    padding: var(--e4);
    color: inherit;
    text-decoration: none;
    border-bottom: 1px solid var(--moldura-linha);
}

.lateral__logo {
    width: 40px;
    height: 40px;
    flex: none;
    border-radius: 50%;
    object-fit: cover;
    /* O logótipo é um JPEG com fundo próprio; o anel dá-lhe uma borda limpa
       contra o preto em vez de o deixar a flutuar. */
    box-shadow: 0 0 0 1px var(--moldura-3);
}

.lateral__nome {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.05;
    font-family: var(--display);
    font-size: 0.98rem;
    text-transform: uppercase;
    letter-spacing: 0.045em;
}

.lateral__nome b {
    font-weight: 400;
}

.lateral__nome i {
    font-style: normal;
    color: var(--moldura-texto-2);
}

/* --- Itens --------------------------------------------------------------- */

.lateral__nav {
    display: flex;
}

.nav-item {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--e3);
    /* 48px de alvo: um dedo não acerta em menos. */
    min-height: 48px;
    color: var(--moldura-texto-2);
    text-decoration: none;
    font-size: 0.9rem;
    font-weight: 550;
    transition:
        color 140ms ease,
        background-color 140ms ease;
}

.nav-item .icone {
    flex: none;
}

.nav-item--activa {
    color: var(--moldura-texto);
    background: var(--moldura-2);
}

@media (hover: hover) and (pointer: fine) {
    .nav-item:not(.nav-item--activa):hover {
        color: var(--moldura-texto);
        background: var(--moldura-2);
    }
}

/* --- Perfil -------------------------------------------------------------- */

.lateral__util {
    padding: var(--e3);
    border-top: 1px solid var(--moldura-linha);
}

.perfil {
    display: flex;
    align-items: center;
    gap: var(--e3);
    width: 100%;
    min-height: 48px;
    padding: var(--e2);
    background: none;
    border: 0;
    border-radius: var(--raio-p);
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: background-color 140ms ease;
}

@media (hover: hover) and (pointer: fine) {
    .perfil:hover {
        background: var(--moldura-2);
    }
}

.perfil__iniciais {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    flex: none;
    border-radius: 50%;
    background: var(--moldura-3);
    font-family: var(--display);
    font-size: 0.82rem;
    letter-spacing: 0.04em;
}

.perfil__texto {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.25;
}

.perfil__nome {
    font-size: 0.88rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.perfil__papel {
    font-size: 0.76rem;
    color: var(--moldura-texto-2);
}

.nav-item__curto {
    display: none;
}

/* ---------------------------------------------------------------------------
   Telemóvel: a barra vai para baixo
   --------------------------------------------------------------------------- */

@media (max-width: 767px) {
    .lateral {
        inset: auto 0 0 0;
        flex-direction: column-reverse;
        border-top: 1px solid var(--moldura-linha);
        /* Acompanha a barra de gestos do iPhone em vez de ficar por baixo dela. */
        padding-bottom: env(safe-area-inset-bottom);
    }

    /* Em baixo não há espaço para a marca nem para o perfil: a marca já está no
       topo do ecrã, e sair vive no menu. */
    .lateral__marca,
    .lateral__util {
        display: none;
    }

    .lateral__nav {
        justify-content: space-around;
    }

    .nav-item {
        flex: 1;
        flex-direction: column;
        justify-content: center;
        gap: 3px;
        min-height: 56px;
        padding: 8px 2px;
        font-size: 0.66rem;
        font-weight: 600;
        text-align: center;
    }

    .nav-item__rotulo {
        display: none;
    }

    .nav-item__curto {
        display: block;
    }

    /* Traço por cima, e não à esquerda: com os itens em coluna, um traço
       lateral não se liga visualmente ao ícone. */
    .nav-item--activa {
        background: none;
    }

    .nav-item--activa::before {
        content: '';
        position: absolute;
        top: 0;
        left: 22%;
        right: 22%;
        height: 2px;
        border-radius: 0 0 2px 2px;
        background: var(--moldura-texto);
    }

    /* Espaço para a barra não tapar o fim das listas. */
    .app__corpo {
        padding-bottom: calc(60px + env(safe-area-inset-bottom));
    }
}

/* ---------------------------------------------------------------------------
   iPad em pé: a barra fica ao lado, só com ícones
   --------------------------------------------------------------------------- */

@media (min-width: 768px) {
    .lateral {
        inset: 0 auto 0 0;
        width: 72px;
        flex-direction: column;
        border-right: 1px solid var(--moldura-linha);
    }

    .app__corpo {
        margin-left: 72px;
    }

    .lateral__nav {
        flex: 1;
        flex-direction: column;
        gap: 2px;
        padding: var(--e2);
        overflow-y: auto;
    }

    .nav-item {
        justify-content: center;
        padding: var(--e2);
        border-radius: var(--raio-p);
    }

    .nav-item__rotulo,
    .nav-item__curto {
        display: none;
    }

    .lateral__marca {
        justify-content: center;
        padding: var(--e4) var(--e2);
    }

    .lateral__nome {
        display: none;
    }

    .perfil {
        justify-content: center;
        padding: var(--e1);
    }

    .perfil__texto {
        display: none;
    }
}

/* ---------------------------------------------------------------------------
   iPad deitado e portátil: cabe o texto
   --------------------------------------------------------------------------- */

@media (min-width: 1024px) {
    .lateral {
        width: 232px;
    }

    .app__corpo {
        margin-left: 232px;
    }

    .nav-item {
        justify-content: flex-start;
        padding: var(--e2) var(--e3);
    }

    .nav-item__rotulo {
        display: block;
    }

    .nav-item--activa::before {
        content: '';
        position: absolute;
        left: 0;
        top: 20%;
        bottom: 20%;
        width: 3px;
        border-radius: 0 3px 3px 0;
        background: var(--moldura-texto);
    }

    .lateral__marca {
        justify-content: flex-start;
    }

    .lateral__nome {
        display: flex;
    }

    .perfil {
        justify-content: flex-start;
        padding: var(--e2);
    }

    .perfil__texto {
        display: flex;
    }
}

/* ===========================================================================
   Topo do painel
   =========================================================================== */

.topo {
    position: sticky;
    top: 0;
    z-index: 40;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--e3);
    padding: var(--e3) var(--e4);
    background: color-mix(in srgb, var(--fundo) 88%, transparent);
    backdrop-filter: blur(14px) saturate(150%);
    -webkit-backdrop-filter: blur(14px) saturate(150%);
    border-bottom: 1px solid var(--linha);
}

.topo__titulo {
    min-width: 0;
}

.topo__titulo h1 {
    font-size: 1.25rem;
    letter-spacing: -0.022em;
}

.topo__contexto {
    margin: 1px 0 0;
    font-size: 0.82rem;
    color: var(--texto-3);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Num telemóvel sobram uns 195px para esta linha e o texto precisa de 273 — as
   reticências comiam metade da informação ("quinta-feira, 27 de agosto · 4…").
   Aqui deixa-se descer para uma segunda linha, que é espaço que o cabeçalho tem
   e a frase não. Mais do que duas continua a cortar, para o título não empurrar
   o conteúdo para fora do ecrã. */
@media (max-width: 767px) {
    .topo__contexto {
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
        line-clamp: 2;
        white-space: normal;
    }
}

.topo__acoes {
    display: flex;
    align-items: center;
    gap: var(--e2);
    flex: none;
}

.icone-botao {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    flex: none;
    padding: 0;
    background: var(--superficie);
    color: var(--texto-2);
    border: 1px solid var(--linha);
    border-radius: var(--raio-p);
    font-size: 1rem;
    cursor: pointer;
    transition:
        background-color 140ms ease,
        color 140ms ease,
        transform 140ms var(--saida);
}

.icone-botao:active {
    transform: scale(0.94);
}

/* Na tira do topo das páginas do aluno, ao lado de botões de 34px. Um quadrado
   de 40px ao lado deles fazia a barra parecer desalinhada. */
.icone-botao--pequeno {
    width: 34px;
    height: 34px;
}

@media (hover: hover) and (pointer: fine) {
    .icone-botao:hover {
        background: var(--superficie-2);
        color: var(--texto);
    }
}

/* Contagem de alertas. Só conta os graves: um sino que acende por tudo ensina
   a ser ignorado. */
.sino__conta {
    position: absolute;
    top: -5px;
    right: -5px;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 9px;
    background: var(--atraso);
    color: #fff;
    font-size: 0.68rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    border: 2px solid var(--fundo);
}

/* Num telemóvel, "QR Codes" e "Sair" não cabem ao lado do título. */
@media (max-width: 600px) {
    .nao-compacto {
        display: none;
    }
}

/* ===========================================================================
   Segmentos: filtros de período
   =========================================================================== */

.segmentos {
    display: flex;
    gap: 3px;
    padding: 3px;
    /* Encolhe até ao conteúdo em vez de esticar por toda a largura. */
    width: max-content;
    max-width: 100%;
    overflow-x: auto;
    scrollbar-width: none;
    background: var(--superficie-2);
    border: 1px solid var(--linha);
    border-radius: 999px;
}

.segmentos::-webkit-scrollbar {
    display: none;
}

.segmento {
    min-height: 36px;
    padding: 7px 14px;
    border: 0;
    border-radius: 999px;
    background: none;
    color: var(--texto-2);
    font: inherit;
    font-size: 0.84rem;
    font-weight: 550;
    white-space: nowrap;
    cursor: pointer;
    transition:
        background-color 140ms ease,
        color 140ms ease;
}

.segmento[aria-pressed='true'] {
    background: var(--marca);
    color: var(--marca-texto);
}

@media (hover: hover) and (pointer: fine) {
    .segmento:not([aria-pressed='true']):hover {
        color: var(--texto);
        background: var(--superficie-3);
    }
}

/* ===========================================================================
   Cartão de painel: título, uma linha de explicação, conteúdo
   =========================================================================== */

.painel-cartao {
    padding: var(--e5);
    background: var(--superficie);
    border: 1px solid var(--linha);
    border-radius: var(--raio);
    box-shadow: var(--sombra-1);
}

.painel-cartao__topo {
    margin-bottom: var(--e4);
}

/* Um cartão de painel que é todo ele um botão. O preenchimento vem do próprio
   cartão, por isso aqui só se tira o aspeto de botão e se dá a área de toque. */
.painel-cartao__abrir {
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.painel-cartao__abrir .painel-cartao__titulo,
.painel-cartao__abrir .painel-cartao__nota,
.painel-cartao__abrir .linha__numero,
.painel-cartao__abrir .linha__meta {
    display: block;
}

.painel-cartao__abrir .painel-cartao__nota {
    text-decoration: underline;
    text-decoration-color: var(--linha-forte);
    text-underline-offset: 3px;
}

.painel-cartao__titulo {
    margin: 0;
    font-size: 1rem;
    font-weight: 650;
    letter-spacing: -0.014em;
}

/* Uma linha, não um parágrafo. Num painel aberto dezenas de vezes por dia, uma
   explicação longa deixa de ser lida à terceira vez e passa a ser ruído. */
.painel-cartao__nota {
    margin: 3px 0 0;
    font-size: 0.84rem;
    color: var(--texto-3);
}

/* --- Métricas em fila ----------------------------------------------------- */

.metricas {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
    gap: var(--e2);
}

.metrica {
    /* Coluna, para a barra poder ser empurrada para o fundo. Sem isso, um
       indicador com linha de contexto empurrava a sua barra para baixo e a fila
       ficava com as barras a três alturas diferentes — lia-se como desalinho e
       não como uma fila. */
    display: flex;
    flex-direction: column;
    /* O `gap` garante o espaço mínimo entre as três partes; o `margin-top: auto`
       da barra come o resto e encosta-a ao fundo. */
    gap: var(--e2);
    padding: var(--e3) var(--e4) var(--e4);
    background: var(--superficie-2);
    border: 1px solid var(--linha);
    border-radius: var(--raio-p);
}

.metrica__rotulo {
    margin: 0;
    font-size: 0.78rem;
    font-weight: 550;
    color: var(--texto-2);
}

.metrica__valor {
    font-size: 1.7rem;
    font-weight: 700;
    letter-spacing: -0.03em;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--cor, var(--texto));
}

/* Barra fina por baixo do número: mostra a proporção sem gastar um gráfico. */
/* A linha de contexto por baixo do número: "menos 53 do que o mês passado".
   Fica em texto pequeno e sem cor — é para ser lida a seguir ao número, não ao
   mesmo tempo. */
.metrica__nota {
    margin: 0;
    font-size: 0.75rem;
    line-height: 1.3;
    color: var(--texto-3);
}

.metrica__barra {
    height: 3px;
    margin-top: auto;
    border-radius: 2px;
    background: var(--linha);
    overflow: hidden;
}

.metrica__barra span {
    display: block;
    height: 100%;
    border-radius: 2px;
    background: var(--cor, var(--texto-3));
    transform-origin: left;
    animation: crescer 620ms var(--saida) both;
}

@keyframes crescer {
    from {
        transform: scaleX(0);
    }
}

/* ===========================================================================
   Menu da conta
   ---------------------------------------------------------------------------
   Aberto do perfil na lateral (ecrãs largos) ou do avatar no topo (telemóvel).
   É um `<dialog>` e não um popover feito à mão: assim vem de graça o fundo
   escurecido, o Esc a fechar e o foco preso lá dentro.

   No telemóvel encosta-se ao fundo, como uma gaveta: é onde o polegar chega.
   Nos ecrãs largos fica ao centro, como qualquer modal.
   =========================================================================== */

.menu {
    width: min(360px, calc(100vw - var(--e4)));
    padding: var(--e4);
    border: 1px solid var(--linha);
    border-radius: var(--raio-g);
    background: var(--superficie);
    color: var(--texto);
    box-shadow: var(--sombra-3);
}

.menu::backdrop {
    background: rgba(16, 20, 19, 0.42);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
}

.menu__cabecalho {
    display: flex;
    align-items: center;
    gap: var(--e3);
    padding-bottom: var(--e4);
    margin-bottom: var(--e3);
    border-bottom: 1px solid var(--linha);
}

.menu__cabecalho .perfil__iniciais {
    background: var(--marca);
    color: var(--marca-texto);
}

.menu__cabecalho .perfil__nome {
    font-size: 1rem;
}

.menu__opcoes {
    display: grid;
    gap: 2px;
    margin-bottom: var(--e4);
}

.menu__opcao {
    display: flex;
    align-items: center;
    width: 100%;
    /* 48px: é um menu para dedo. */
    min-height: 48px;
    padding: var(--e2) var(--e3);
    border: 0;
    border-radius: var(--raio-p);
    background: none;
    color: var(--texto);
    font: inherit;
    font-size: 0.94rem;
    font-weight: 550;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 140ms ease;
}

@media (hover: hover) and (pointer: fine) {
    .menu__opcao:hover {
        background: var(--superficie-2);
    }
}

.menu__opcao:active {
    background: var(--superficie-3);
}

.menu__opcao--perigo {
    color: var(--atraso);
}

/* Uma opção com explicação empilha o rótulo e a nota em vez de os alinhar
   lado a lado, senão a nota empurrava o rótulo e as linhas ficavam todas com
   comprimentos diferentes. */
.menu__opcao:has(.menu__opcao-nota) {
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 1px;
    padding-top: var(--e2);
    padding-bottom: var(--e2);
}

.menu__opcao-nota {
    font-size: 0.79rem;
    font-weight: 400;
    color: var(--texto-3);
}

/* Uma opção que representa um assunto — um alerta — leva o ponto de estado à
   esquerda, como os indicadores do painel. A cor não está sozinha: o texto ao
   lado diz sempre do que se trata. */
/* O ponto vive no rótulo e não na opção: preso à opção, ficava no meio vertical
   da caixa e, num título de duas linhas, aparecia ao lado da segunda. Assim
   assenta sempre na primeira linha, e o resto do título fica indentado por
   baixo. */
.menu__opcao--marcada .menu__opcao-rotulo {
    display: flex;
    align-items: baseline;
    gap: var(--e2);
}

.menu__opcao--marcada .menu__opcao-rotulo::before {
    content: '';
    flex: none;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--cor, var(--neutro));
    /* A linha de base de uma caixa vazia é o seu fundo; sobe-se o ponto para o
       meio da altura da letra. */
    transform: translateY(-2px);
}

/* Numa folha, o vazio fica com ar de conteúdo e não de erro. */
.menu__opcoes .vazio {
    margin: 0;
    padding: var(--e5) var(--e3);
    text-align: center;
}

/* Na opção de apagar, o vermelho é do rótulo; a explicação continua a ser
   texto de apoio e não um segundo alarme. */
.menu__opcao--perigo .menu__opcao-nota {
    color: var(--texto-3);
}

/* Avatar pequeno, para o botão do topo no telemóvel. */
.perfil__iniciais--pequenas {
    width: 26px;
    height: 26px;
    font-size: 0.7rem;
    background: var(--marca);
    color: var(--marca-texto);
}

/* Só existe onde a lateral não tem espaço para o perfil. */
.so-movel {
    display: none;
}

@media (max-width: 767px) {
    .so-movel {
        display: flex;
    }

    /* Gaveta: encostada ao fundo, larga, e acima da barra de gestos. */
    .menu {
        width: 100%;
        max-width: none;
        margin: auto auto 0;
        border-radius: var(--raio-g) var(--raio-g) 0 0;
        border-bottom: 0;
        padding-bottom: calc(var(--e4) + env(safe-area-inset-bottom));
        animation: gaveta 220ms var(--saida);
    }

    @keyframes gaveta {
        from {
            transform: translateY(100%);
        }
    }
}


/* ===========================================================================
   Mapa de aulas
   ---------------------------------------------------------------------------
   O cartaz do ginásio é uma grelha de seis colunas. Aqui as colunas existem
   onde há largura para elas e empilham-se num telemóvel: seis colunas num ecrã
   de 380px seriam ilegíveis, e é no telemóvel que este painel vive.

   Sem cor a distinguir os tipos de aula, ao contrário do cartaz. A cor neste
   sistema quer dizer uma coisa só — o estado do pagamento — e gastá-la aqui
   para separar "Kick Kids" de "Kickboxing K1" tirava-lhe esse significado. Os
   nomes chegam.
   =========================================================================== */

.horario {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
    gap: var(--e2);
    align-items: start;
}

/* Num iPad em pé cabem quatro colunas, e seis dias em quatro colunas dão uma
   fila de quatro e outra de dois, com um buraco no meio do cartaz. Três colunas
   dão duas filas iguais — que é como o horário está afixado na parede. */
@media (min-width: 768px) and (max-width: 1100px) {
    .horario {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

.horario__dia {
    display: grid;
    gap: 6px;
    align-content: start;
}

.horario__nome {
    margin: 0 0 2px;
    padding-bottom: var(--e2);
    border-bottom: 1px solid var(--linha);
    font-size: 0.74rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--texto-3);
}

.horario__aula {
    display: grid;
    gap: 1px;
    padding: var(--e3);
    text-align: left;
    font: inherit;
    color: inherit;
    background: var(--superficie-2);
    border: 1px solid var(--linha);
    border-radius: var(--raio-p);
    cursor: pointer;
    transition:
        background-color 140ms ease,
        border-color 140ms ease,
        transform 140ms var(--saida);
}

@media (hover: hover) and (pointer: fine) {
    .horario__aula:hover {
        background: var(--superficie-3);
        border-color: var(--linha-forte);
    }
}

.horario__aula:active {
    transform: scale(0.98);
}

.horario__hora {
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    line-height: 1.15;
}

.horario__titulo {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--texto-2);
}

.horario__duracao {
    font-size: 0.74rem;
    color: var(--texto-3);
    font-variant-numeric: tabular-nums;
}

/* Suspensa: fica no mapa, mas apagada. Tirá-la de todo faria perder a memória
   de que existe e há-de voltar. */
.horario__aula--inativa {
    opacity: 0.5;
    border-style: dashed;
}

.horario__pausa {
    margin-top: 2px;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--texto-3);
}

/* ===========================================================================
   Movimento reduzido
   ===========================================================================
   Menos movimento não é nenhum movimento: mantêm-se as mudanças de opacidade,
   que ajudam a perceber o que apareceu, e tira-se tudo o que se desloca. */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-delay: 0ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }

    /* Estes são desenhados por `stroke-dashoffset` — sem animação teriam de
       ficar visíveis, senão o ecrã de check-in aparecia vazio. */
    .disco__arco,
    .disco__marca path {
        stroke-dashoffset: 0 !important;
    }

    .disco::before {
        opacity: 1;
    }

    .esqueleto::after {
        display: none;
    }
}

/* ===========================================================================
   A ficha do aluno
   ===========================================================================
   Uma coluna de 430px num telemóvel, e quatro perguntas repartidas por abas.
   Tudo o que se segue existe para essa coluna: os títulos com ícone que se
   encontram sem serem lidos, as horas alinhadas numa coluna própria, e um só
   sítio por linha onde carregar. */

/* --- Saudação ------------------------------------------------------------- */

.saudacao {
    display: flex;
    align-items: center;
    gap: var(--e3);
    margin-bottom: var(--e5);
}

.saudacao__texto {
    min-width: 0;
}

.saudacao__texto h1 {
    /* O nome é a primeira coisa da página; a linha por baixo é contexto e não
       pode empurrá-la para longe. */
    margin-bottom: 2px;
}

.saudacao__texto p {
    margin: 0;
}

/* --- Títulos de secção ---------------------------------------------------- */
/* Um rótulo em versaletes com o ícone à frente. Numa ficha com sete secções
   repartidas por quatro abas, o ícone é o que deixa reencontrar a secção que se
   procura sem ler os títulos todos — e não é decoração: nenhuma secção o
   partilha com outra. */

.seccao__topo {
    margin-bottom: var(--e3);
}

.seccao__titulo {
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 0;
    margin-right: auto;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--texto-3);
}

/* O ícone acompanha o texto: um pouco maior do que a letra em versaletes, para
   não parecer um acento. */
.seccao__titulo .icone {
    flex: none;
    opacity: 0.9;
}

/* Todos os ícones dentro de texto assentam na linha em vez de ficarem pendurados
   da base, que é o que um `<svg>` faz por omissão. */
.icone {
    vertical-align: middle;
}

/* --- Abas ----------------------------------------------------------------- */
/* Ficam coladas ao topo ao rolar: numa aba longa — o histórico de treinos — a
   forma de sair dali não pode ser voltar ao princípio da página.
   As margens negativas levam a barra às bordas do `main` para o fio de baixo
   atravessar a coluna toda, e não parar no padding. */

.abas {
    position: sticky;
    top: 0;
    z-index: 30;
    display: flex;
    margin: 0 calc(-1 * var(--e4)) var(--e5);
    padding: 0 var(--e4);
    background: color-mix(in srgb, var(--fundo) 88%, transparent);
    backdrop-filter: blur(12px) saturate(150%);
    -webkit-backdrop-filter: blur(12px) saturate(150%);
    border-bottom: 1px solid var(--linha);
}

.aba {
    flex: 1;
    /* Ícone por cima do rótulo, e não ao lado: lado a lado, "Progresso" com o
       ícone à frente precisa de 93px, e num telemóvel de 390px cada uma das
       quatro abas só tem 89. Empilhado cabe em qualquer largura, e é a forma
       que toda a gente já conhece de uma barra de separadores.
       58px: é uma barra para dedo. */
    min-height: 58px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: var(--e2) 4px;
    border: 0;
    /* O traço existe sempre, transparente, para a aba não saltar 2px ao ficar
       escolhida. */
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    background: none;
    color: var(--texto-3);
    font: inherit;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.005em;
    cursor: pointer;
    transition:
        color 140ms ease,
        border-color 140ms ease;
}

.aba .icone {
    flex: none;
}

.aba[aria-selected='true'] {
    color: var(--texto);
    border-bottom-color: var(--marca);
}

@media (hover: hover) and (pointer: fine) {
    .aba:not([aria-selected='true']):hover {
        color: var(--texto-2);
    }
}

/* ===========================================================================
   Próximas aulas
   ===========================================================================
   O dia inteiro, e não só a aula que calha primeiro: quem treina às 20:15 tem
   de poder avisar dessa aula, não da das 19:00.

   Três colunas: a hora, o que é e quem dá, e o botão. A hora à esquerda em
   algarismos tabulares é o que faz as aulas de um dia lerem-se como um horário
   e não como três cartões soltos. */

.etiqueta-dia {
    flex: none;
    padding: 4px 10px;
    border-radius: 999px;
    background: var(--marca);
    color: var(--marca-texto);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
}

.aulas {
    display: grid;
    gap: var(--e2);
}

.aula {
    position: relative;
    display: grid;
    /* A aula cresce, o botão de "conto ir" fica ao seu tamanho. */
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--e2);
    padding: 6px var(--e3) 6px 0;
    background: var(--superficie);
    border: 1px solid var(--linha);
    border-radius: var(--raio);
    box-shadow: var(--sombra-1);
    transition:
        border-color 160ms ease,
        box-shadow 160ms ease;
}

/* A aula inteira é um botão: abre a lista de quem disse que vai. O
   preenchimento vive aqui e não na `.aula` para a área de toque chegar às
   bordas do cartão — um alvo que só cobre o texto obriga a apontar. */
.aula__abrir {
    display: grid;
    grid-template-columns: 3.3rem minmax(0, 1fr);
    align-items: center;
    gap: var(--e3);
    min-width: 0;
    padding: var(--e3) var(--e2) var(--e3) var(--e3);
    border: 0;
    border-radius: var(--raio);
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: background-color 140ms ease;
}

@media (hover: hover) and (pointer: fine) {
    .aula__abrir:hover {
        background: var(--superficie-2);
    }
}

.aula__abrir:active {
    background: var(--superficie-3);
}

/* O mesmo traço de estado das listas, pela mesma razão: lê-se ao percorrer sem
   pesar como uma barra inteira. Aqui diz "já disseste que vais". */
.aula::before {
    content: '';
    position: absolute;
    left: 0;
    top: 50%;
    width: 3px;
    height: 0;
    border-radius: 0 3px 3px 0;
    background: var(--cor, transparent);
    transform: translateY(-50%);
    transition: height 180ms var(--saida);
}

.aula--vou::before {
    height: 52%;
}

.aula--vou {
    border-color: var(--cor-linha, var(--linha-forte));
}

.aula__hora {
    display: flex;
    flex-direction: column;
    gap: 1px;
    text-align: left;
}

.aula__horas,
.aula__duracao,
.aula__nome {
    display: block;
}

.aula__horas {
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
}

.aula__duracao {
    font-size: 0.72rem;
    color: var(--texto-3);
    font-variant-numeric: tabular-nums;
}

.aula__corpo {
    min-width: 0;
}

.aula__nome {
    margin: 0;
    font-size: 0.97rem;
    font-weight: 650;
    letter-spacing: -0.012em;
    /* Quebra em vez de cortar com reticências: o nome da aula é a razão de ser
       da linha, e num ecrã de 320px "Kickboxing K1" ficaria em "Kickboxi…". */
    overflow-wrap: anywhere;
}

/* Quem dá a aula. É a informação que faltava — vem logo por baixo do nome, e
   não perdida no fim da linha ao lado da duração. */
.aula__quem {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 5px;
    margin: 3px 0 0;
    font-size: 0.82rem;
    font-weight: 550;
    color: var(--texto-2);
    min-width: 0;
}

.aula__quem .icone {
    flex: none;
    color: var(--texto-3);
}

.aula__conta {
    display: block;
    margin: 2px 0 0;
    font-size: 0.76rem;
    color: var(--texto-3);
    text-decoration: underline;
    text-decoration-color: var(--linha-forte);
    text-underline-offset: 3px;
}

.aula__botao {
    flex: none;
    white-space: nowrap;
}

/* ===========================================================================
   Mapa de aulas
   ===========================================================================
   Uma lista por dias, e não a grelha de seis colunas do painel: numa coluna de
   430px a grelha dá duas colunas por linha e o cartaz desfaz-se.
   O que faz um horário ler-se é as horas alinharem numa coluna própria — daí a
   largura fixa e os algarismos tabulares. */

.semana {
    display: grid;
    gap: var(--e5);
}

/* Cada dia é uma `<section>`, e a regra geral `section + section` somava 32px
   ao intervalo da grelha — os dias ficavam ao dobro da distância um do outro
   do que a folha diz aqui. Quem manda no espaçamento é o `gap`. */
.semana > section + section {
    margin-top: 0;
}

.semana__nome {
    display: flex;
    align-items: center;
    gap: var(--e2);
    margin: 0 0 var(--e2);
    padding-bottom: var(--e2);
    border-bottom: 1px solid var(--linha);
    font-size: 0.76rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--texto-3);
}

/* O dia de hoje puxa-se para a frente com tinta, não com cor: o verde e o
   vermelho desta app querem dizer pago e em atraso. */
.semana__dia--hoje .semana__nome {
    color: var(--texto);
    border-bottom-color: var(--texto);
}

.semana__hoje {
    padding: 2px 7px;
    border-radius: 999px;
    background: var(--marca);
    color: var(--marca-texto);
    font-size: 0.68rem;
    letter-spacing: 0.06em;
}

.semana__aulas {
    list-style: none;
    margin: 0;
    padding: 0;
}

.aula-linha {
    display: grid;
    /* Hora fixa, nome a crescer, o resto ao seu tamanho. É esta coluna fixa
       que faz as horas alinharem de dia para dia. */
    grid-template-columns: 3.4rem minmax(0, 1fr) auto;
    align-items: baseline;
    gap: var(--e3);
    padding: 10px 0;
    border-bottom: 1px solid var(--linha);
}

.semana__aulas li:last-child {
    border-bottom: 0;
}

.aula-linha__hora {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}

.aula-linha__corpo {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.aula-linha__nome {
    display: flex;
    align-items: baseline;
    gap: var(--e2);
    flex-wrap: wrap;
    min-width: 0;
    font-weight: 550;
}

/* Quem dá a aula, por baixo do nome. No fim da linha, ao lado da duração,
   ficavam duas coisas sem relação a disputar a mesma coluna estreita. */
.aula-linha__quem {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 0.79rem;
    color: var(--texto-3);
}

.aula-linha__quem .icone {
    flex: none;
}

.aula-linha__fim {
    font-size: 0.79rem;
    color: var(--texto-3);
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* A que vem a seguir, marcada onde já se está a olhar. */
.aula-linha--proxima .aula-linha__hora {
    color: var(--marca);
}

.aula-linha__marca {
    padding: 1px 7px;
    border-radius: 999px;
    background: var(--marca-tenue);
    color: var(--texto-2);
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/* ===========================================================================
   Progresso do aluno
   =========================================================================== */
/* A barra é o elemento com mais peso da página do aluno, e por isso é a única
   coisa desta secção com altura a sério. O resto — a sequência, o total, a
   meta mais próxima — é contexto e fica em texto pequeno. */

.progresso {
    height: 10px;
    margin: var(--e3) 0;
    border-radius: 999px;
    background: var(--superficie-3);
    overflow: hidden;
}

.progresso > span {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: var(--cor, var(--marca));
    /* Cresce ao entrar, como o contador ao lado conta. Uma barra que aparece
       cheia não diz que se chegou ali. */
    animation: encher 700ms var(--saida) both;
}

@keyframes encher {
    from {
        transform: scaleX(0);
        transform-origin: left;
    }
}

/* Dentro de uma meta, a barra é uma indicação e não o assunto. */
.progresso--fino {
    height: 5px;
    margin: 6px 0 4px;
}

.progresso__titulo {
    margin: 0;
    font-size: 0.95rem;
    color: var(--texto-2);
}

.progresso__numero {
    font-size: 1.9rem;
    font-weight: 700;
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    color: var(--cor, var(--texto));
}

.progresso__de {
    font-weight: 550;
}

/* --- Marcas: sequência, total, meta mais próxima -------------------------- */
/* Em linha e a quebrar, para caberem três num telemóvel sem virarem uma lista.
   Sem cor: o verde e o vermelho desta app querem dizer pago e em atraso, e a
   sequência de treinos não é nem uma coisa nem outra — quem a distingue é o
   ícone. */

.marcas {
    display: flex;
    flex-wrap: wrap;
    gap: var(--e2);
    margin-top: var(--e3);
}

.marca {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 10px;
    border-radius: 999px;
    background: var(--superficie-2);
    border: 1px solid var(--linha);
    font-size: 0.79rem;
    font-weight: 550;
    color: var(--texto-2);
}

.marca .icone {
    flex: none;
    color: var(--texto-3);
}

/* --- Situação, em duas linhas --------------------------------------------- */
/* Rótulo à esquerda, resposta à direita: lê-se de relance, que é tudo o que se
   quer de um bloco que já não é o assunto principal da página. */

/* Um assunto por bloco, com um fio a separá-los. Sem o fio, as linhas de
   apoio de um encostavam ao rótulo do outro e pareciam ser dele. */
.estado-bloco + .estado-bloco {
    margin-top: var(--e3);
    padding-top: var(--e3);
    border-top: 1px solid var(--linha);
}

.estado-linha {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--e3);
}

.estado-bloco .linha__meta {
    margin: 4px 0 0;
}

.estado-linha__rotulo {
    font-size: 0.79rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--texto-3);
    white-space: nowrap;
}

.estado-linha__valor {
    /* Flex por causa do triângulo de aviso que acompanha os estados vermelhos:
       um `<svg>` solto dentro de texto assenta na base da linha e ficava a
       pender por baixo da palavra. */
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
    font-weight: 650;
    text-align: right;
    color: var(--cor, var(--texto));
    min-width: 0;
    overflow-wrap: anywhere;
}

.estado-linha__valor .icone {
    flex: none;
}

/* Os dados pessoais usam a mesma linha, empilhados com um fio entre cada um. */
.estado-linha--dado + .estado-linha--dado {
    margin-top: var(--e3);
    padding-top: var(--e3);
    border-top: 1px solid var(--linha);
}

/* Uma meta é uma linha sem retrato nem número ao fim: o que interessa é o nome
   e a barra por baixo dele. */
.linha--meta {
    align-items: stretch;
}

.linha--meta .linha__nome {
    display: flex;
    align-items: center;
    gap: 6px;
}

.linha--meta .linha__nome .icone {
    flex: none;
    color: var(--cor, var(--texto-3));
}

/* ===========================================================================
   Ranking
   =========================================================================== */
/* O lugar vem antes do retrato porque é por ele que se lê a tabela: o olho
   desce a coluna dos números e só depois procura a cara. Largura fixa para os
   três primeiros — com distintivo ou sem ele — não desalinharem os nomes. */

.lugar {
    flex: none;
    width: 30px;
    text-align: center;
    font-size: 1.05rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--texto-3);
}

/* Os três primeiros lugares levam um distintivo redondo em vez do número solto.
   Substitui as medalhas em emoji, que cada sistema operativo desenhava à sua
   maneira e que obrigavam a adivinhar a posição pela cor — aqui o número
   continua lá escrito, e o peso do distintivo é que diz o pódio.
   Em tinta e não em dourado: nesta aplicação a cor quer dizer pago ou em
   atraso, e um terceiro significado tirava-lhe o valor aos outros dois. */
.lugar--podio {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    font-size: 0.9rem;
    line-height: 1;
}

.lugar--1 {
    background: var(--marca);
    color: var(--marca-texto);
}

.lugar--2 {
    background: var(--superficie-3);
    color: var(--texto);
    box-shadow: inset 0 0 0 1px var(--linha-forte);
}

.lugar--3 {
    background: var(--superficie-2);
    color: var(--texto-2);
    box-shadow: inset 0 0 0 1px var(--linha);
}

.linha--podio {
    border-color: var(--linha-forte);
}

/* O prémio de um lugar não é um estado do aluno — não leva verde nem vermelho,
   que aqui querem dizer "pago" e "em atraso". Leva o peso do texto e o ícone. */
.linha__meta--premio {
    display: flex;
    align-items: center;
    gap: 5px;
    color: var(--texto-2);
    font-weight: 550;
}

.linha__meta--premio .icone {
    flex: none;
    color: var(--texto-3);
}

/* Um prémio suspenso continua na lista para se poder voltar a ligar, mas não
   compete com os que estão a valer. */
.linha--apagada {
    opacity: 0.55;
}

/* O seletor de mês encolhe até ao conteúdo em vez de esticar pela linha toda:
   ao lado dos segmentos, um campo com 100% empurrava-os para fora. */
.campo--linha {
    flex: none;
    min-width: 0;
}

.campo--linha select {
    width: auto;
    max-width: 100%;
}

/* --- O ranking na página do aluno ---------------------------------------- */
/* A linha do próprio aluno fica marcada: numa lista de dez nomes, encontrar-se
   a si mesmo não pode dar trabalho. */
.linha--eu {
    background: var(--marca-tenue);
    border-color: var(--marca);
}

.linha--eu .linha__nome::after {
    content: ' · tu';
    font-weight: 400;
    color: var(--texto-3);
}

/* ===========================================================================
   Cobrar a vários
   =========================================================================== */
/* A barra fica agarrada ao fundo do ecrã porque é lá que está o polegar depois
   de percorrer a lista, e a conta do que está escolhido fica sempre à vista —
   ninguém pode acabar a cobrar a alguém que não sabe que escolheu.

   Num telemóvel senta-se por cima da barra de navegação em vez de a tapar: as
   cinco secções continuam a alcance de um toque, e o `env(safe-area-inset)`
   mantém tudo acima da barra de gestos do iPhone. */

.barra-seleccao {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 70;
    display: flex;
    align-items: center;
    gap: var(--e3);
    flex-wrap: wrap;
    padding: var(--e3) var(--e4);
    background: var(--moldura);
    color: var(--moldura-texto);
    border-top: 1px solid var(--moldura-linha);
    box-shadow: var(--sombra-3);
    animation: subir 220ms var(--saida) both;
}


.barra-seleccao__conta {
    flex: 1;
    min-width: 0;
    font-size: 0.88rem;
    font-weight: 600;
}

.barra-seleccao__accoes {
    display: flex;
    gap: var(--e2);
    flex: none;
}

/* A barra vive na moldura escura, e os botões têm de se inverter com ela. O
   botão principal é preto em todo o resto do painel — aqui, preto sobre preto
   é um botão que não se vê. Trocam-se as tintas: claro por baixo, escuro por
   cima, que é a mesma hierarquia lida ao contrário. */
.barra-seleccao .botao {
    background: var(--moldura-texto);
    color: var(--moldura);
    border-color: var(--moldura-texto);
}

.barra-seleccao .botao--linha {
    color: var(--moldura-texto);
    border-color: var(--moldura-linha);
    background: none;
}

/* Desativado tem de se ver que está desativado, e num fundo escuro a opacidade
   sozinha não chega — o botão ficava só um pouco mais apagado. */
.barra-seleccao .botao:disabled {
    background: none;
    color: var(--moldura-texto-2);
    border-color: var(--moldura-linha);
    cursor: not-allowed;
}

@media (max-width: 767px) {
    .barra-seleccao {
        bottom: calc(60px + env(safe-area-inset-bottom));
    }

    /* Espaço para a barra não tapar o último aluno da lista. */
    .a-seleccionar {
        padding-bottom: 72px;
    }
}

@media (min-width: 768px) {
    .barra-seleccao {
        left: 72px;
    }
}

/* O mesmo ponto de corte que a barra lateral usa para abrir. */
@media (min-width: 1024px) {
    .barra-seleccao {
        left: 232px;
    }
}

/* Uma linha escolhida. O traço de estado à esquerda continua a dizer se ela
   está paga; o que muda é a moldura, para os dois sinais não se atrapalharem. */
.a-seleccionar .linha {
    cursor: pointer;
}

.linha[aria-pressed='true'] {
    background: var(--marca-tenue);
    border-color: var(--marca);
    box-shadow: inset 0 0 0 1px var(--marca);
}

/* ===========================================================================
   Ecrãs de toque
   =========================================================================== */
/* Um rato acerta num alvo de 34px sem pensar duas vezes; um polegar não, e o
   painel é usado sobretudo no telemóvel e no iPad. Nos ecrãs de toque os botões
   pequenos e os segmentos passam a 44px, que é o mínimo que a Apple recomenda e
   o que a Google chama de alvo confortável. No portátil ficam como estão: aí a
   compactação é uma vantagem, e não um risco de carregar no botão errado.

   Fica no fim do ficheiro de propósito. `.botao--pequeno` e `.segmento` têm
   a mesma especificidade que isto, e entre iguais ganha a última — posto
   antes das regras que ajusta, este bloco não fazia absolutamente nada. */

@media (pointer: coarse) {
    .botao--pequeno {
        min-height: 44px;
        padding: 9px 14px;
    }

    .segmento {
        min-height: 44px;
        padding: 11px 16px;
    }

    /* "Já tens conta? Entra aqui." — um link dentro de uma frase não pode ter
       44px de altura sem partir a linha em que vive, e as regras de
       acessibilidade abrem-lhe exceção por isso mesmo. O que se pode fazer é
       alargar a área que responde ao toque sem mexer no desenho: a margem
       negativa devolve ao texto o espaço que o padding lhe tirou, por isso a
       frase fica exatamente onde estava e o alvo passa a ter 44px de altura. */
    main p > a:not([class]) {
        display: inline-block;
        padding: 12px 4px;
        margin: -12px -4px;
    }

    /* Os nomes na tabela de pagamentos são links para a ficha do aluno, e uma
       linha de texto tem 16px de altura — num iPad, acerta-se neles por sorte.
       A célula já é alta que chegue; o que faltava era o link ocupá-la. Mesmo
       truque: padding a crescer, margem negativa a devolver o espaço, e a
       tabela fica com as linhas exatamente da altura que tinha. */
    .tabela a {
        display: inline-block;
        padding: 12px 2px;
        margin: -12px -2px;
    }
}
