:root {
  --fundo: #faf6f0;
  --superficie: #fffdf9;
  --texto: #2b1d14;
  --suave: #7a6656;
  --linha: #e6dccf;
  --acento: #7b3f22;
  --acento-texto: #fffaf3;
  --erro: #a8322d;
  --erro-fundo: #fbeceb;
  /* Dos botões que não têm volta: mais forte que o `--erro` das mensagens, para chamar a atenção. */
  --perigo: #cf222e;
  --perigo-escuro: #a40e26;
  --tingido: color-mix(in srgb, var(--acento) 8%, var(--superficie));
  --tingido-borda: color-mix(in srgb, var(--acento) 40%, var(--linha));
  /* Do recém-criado: amarelo de marca-texto, porque o tingido mal se distingue da listra. */
  --destaque: #fbe8a0;
  /* Das tabelas, do mais claro ao mais escuro: a linha par, a do dia no board e o cabeçalho. */
  --listra: color-mix(in srgb, var(--linha) 30%, var(--superficie));
  --subcabecalho: #f2eadf;
  --cabecalho: #ede3d5;
  --cabecalho-texto: color-mix(in srgb, var(--suave) 50%, var(--texto));
  /* Escala de texto, do menor ao maior. */
  --fonte-minima: 0.75rem;
  --fonte-pequena: 0.875rem;
  --fonte-normal: 1rem;
  --fonte-subtitulo: 1.25rem;
  --fonte-titulo: 1.5rem;
  --fonte-titulo-grande: 2rem;
  /* Escala de espaços entre blocos, do menor ao maior. O padding de dentro dos controles fica de fora: dá a
     altura deles. */
  --espaco-minimo: 0.25rem;
  --espaco-pequeno: 0.5rem;
  --espaco-medio: 0.75rem;
  --espaco-grande: 1.5rem;
  --raio: 10px;
  --raio-cartao: 14px;
  /* A da `.topo`, sem a borda: o que fica fixo logo abaixo dela se alinha por aqui. */
  --altura-topo: calc(3.25rem + env(safe-area-inset-top));
  --serifa: ui-serif, "New York", Georgia, serif;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color-scheme: light;
}

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

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--fundo);
  color: var(--texto);
  font: var(--fonte-normal) / 1.5 var(--sans);
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom)
    env(safe-area-inset-left);
}

main {
  flex: 1;
  width: 100%;
  max-width: 80rem;
  margin: 0 auto;
  padding: 1.5rem 1.25rem 2rem;
}

h1,
h2 {
  font-family: var(--serifa);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
}

h1 {
  font-size: var(--fonte-titulo-grande);
  margin: 0 0 var(--espaco-grande);
}

label {
  display: grid;
  gap: var(--espaco-minimo);
  font-size: var(--fonte-pequena);
  font-weight: 600;
}

/* Abaixo de 16px o Safari do iOS dá zoom ao focar o campo. */
input,
select,
textarea {
  font: inherit;
  font-size: var(--fonte-normal);
  font-weight: 400;
  color: inherit;
  width: 100%;
  min-height: 2.25rem;
  padding: 0.25rem 0.625rem;
  background: var(--superficie);
  border: 1px solid var(--linha);
  border-radius: var(--raio);
  appearance: none;
}

textarea {
  resize: vertical;
  padding-block: 0.375rem;
}

/* O appearance: none tira a seta nativa. */
select {
  padding-right: 2rem;
  background: var(--superficie)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='8'%3E%3Cpath d='M1 1l6 6 6-6' fill='none' stroke='%237a6656' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")
    no-repeat right 0.75rem center;
}

input[type="color"] {
  flex: none;
  width: 3rem;
  padding: 0.25rem;
  cursor: pointer;
}

/* A cor em texto e o seletor lado a lado. */
.cor {
  display: flex;
  gap: var(--espaco-pequeno);
}

input[type="checkbox"] {
  appearance: auto;
  width: 1.25rem;
  height: 1.25rem;
  min-height: 0;
  margin: 0;
  accent-color: var(--acento);
}

/* As setas do número são pequenas demais para o dedo; o teclado numérico basta. */
input[type="number"] {
  appearance: textfield;
}

input[type="number"]::-webkit-inner-spin-button {
  appearance: none;
  margin: 0;
}

/* O Safari do iOS centra a data e encolhe o campo vazio. */
input[type="date"]::-webkit-date-and-time-value,
input[type="datetime-local"]::-webkit-date-and-time-value {
  text-align: left;
}

input:disabled,
select:disabled {
  color: var(--suave);
  background-color: transparent;
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--acento);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--acento) 18%, transparent);
}

button,
.botao,
.secundario {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--espaco-pequeno);
  font: inherit;
  font-size: var(--fonte-pequena);
  font-weight: 600;
  min-height: 2.25rem;
  padding: 0.25rem 0.875rem;
  border-radius: var(--raio);
  border: 1px solid transparent;
  background: var(--acento);
  color: var(--acento-texto);
  cursor: pointer;
  touch-action: manipulation;
}

/* Num link com cara de botão: `.botao` é o primário; o secundário serve aos dois, como o do WhatsApp. */
.botao,
.secundario {
  text-decoration: none;
}

.secundario {
  border-color: var(--linha);
  background: transparent;
  color: var(--acento);
}

:is(button, .botao, .secundario, summary):focus-visible,
.filtros .chip:has(:focus-visible) {
  outline: 3px solid color-mix(in srgb, var(--acento) 35%, transparent);
  outline-offset: 2px;
}

.icone {
  width: 1.125rem;
  height: 1.125rem;
  flex: none;
  vertical-align: -0.25em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Logótipo com as cores próprias, sem o traço dos outros ícones. A borda branca do original
   sumia no fundo claro do botão; ganha um contorno fino por fora. */
.icone.marca {
  width: 1.25rem;
  height: 1.25rem;
  stroke: none;
}

.icone.marca .borda {
  fill: #fff;
  stroke: currentColor;
  stroke-width: 1px;
  vector-effect: non-scaling-stroke;
}

button:active {
  filter: brightness(0.92);
}

button:not(.secundario):disabled {
  background: color-mix(in srgb, var(--acento) 55%, var(--superficie));
}

.secundario:disabled {
  color: var(--suave);
}

.secundario.perigo:not(:disabled) {
  border-color: var(--perigo);
  color: var(--perigo);
}

/* O círculo cobre o ícone e só aparece depois do atraso: a resposta rápida trocaria o ícone
   e o destrocaria logo a seguir. */
.carrega {
  position: relative;
}

.carrega::before {
  content: "";
  position: absolute;
  top: calc(50% - 0.5625rem);
  left: 0.875rem;
  width: 1.125rem;
  height: 1.125rem;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  opacity: 0;
  animation: girar 0.8s linear infinite;
}

.carrega.htmx-request {
  cursor: progress;
}

.carrega.htmx-request::before,
.carrega.htmx-request .icone {
  transition: opacity 0.1s 0.15s;
}

.carrega.htmx-request::before {
  opacity: 1;
}

.carrega.htmx-request .icone {
  opacity: 0;
}

/* Sem ícone, o círculo fica no meio e esconde o texto. Só o desenho do texto some: a cor continua
   a do botão, que é a do círculo. O texto some de uma vez, e não esmaecendo: esmaecendo, ficaria
   por baixo do círculo enquanto ele aparece. */
.carrega:not(:has(.icone))::before {
  left: calc(50% - 0.5625rem);
}

.carrega.htmx-request:not(:has(.icone)) {
  -webkit-text-fill-color: transparent;
  transition: -webkit-text-fill-color 0s 0.15s;
}

@keyframes girar {
  to {
    transform: rotate(1turn);
  }
}

/* O "A guardar alteração…" do formulário que salva sozinho (`app.js`) espera o mesmo que o círculo. */
[role="status"][data-a-guardar] {
  animation: surgir 0.1s 0.15s backwards;
}

@keyframes surgir {
  from {
    opacity: 0;
  }
}

/* O checkbox que salva sozinho não tem o círculo do `.carrega`: fica esmaecido enquanto espera. */
input[type="checkbox"].htmx-request {
  opacity: 0.5;
  cursor: progress;
}

/* A lista que o filtro, a pesquisa ou a paginação refazem (o `hx-indicator` aponta para ela)
   esmaece enquanto a resposta não chega. No filho porque o display: contents não tem caixa para
   a opacidade; o atraso deixa de fora a resposta rápida, que só piscaria. A nova (htmx-added)
   entra antes de a classe sair: o settle do htmx espera um setTimeout entre os dois. */
.recarrega.htmx-request > :not(.htmx-added) {
  opacity: 0.5;
  transition: opacity 0.2s 0.15s;
}

/* O recém-criado fica amarelo por um instante e esmaece. A pausa é para o olho chegar a tempo
   quando o diálogo fecha por cima. Sem `to`: termina no fundo que já seria o dele (a listra, o
   cartão). Na linha, nas células, que têm a listra por cima da `tr`. */
:is(tr[data-criado] > td, :not(tr)[data-criado]) {
  animation: criado 1.8s;
}

@keyframes criado {
  from,
  33% {
    background-color: var(--destaque);
  }
}

/* Só com rato: no toque o hover fica preso depois de soltar o dedo. */
@media (hover: hover) {
  :is(button, .botao):not(:is(:disabled, [aria-disabled="true"])):hover {
    background: color-mix(in srgb, var(--acento) 85%, black);
  }

  .secundario:not(:is(:disabled, [aria-disabled="true"])):hover,
  .filtros .chip:hover {
    border-color: var(--tingido-borda);
    background: var(--tingido);
  }

  .secundario.perigo:not(:is(:disabled, [aria-disabled="true"])):hover {
    border-color: var(--perigo-escuro);
    background: var(--perigo-escuro);
    color: var(--acento-texto);
  }
}

/* Antes do `.botoes`, que lhe acrescenta a margem. */
form [role="status"] {
  margin: 0;
  color: var(--suave);
  font-size: var(--fonte-normal);
}

/* A barra de botões do fim de um formulário: o principal à direita. */
.botoes {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--espaco-pequeno);

  [role="status"] {
    margin-right: var(--espaco-pequeno);
  }

  /* No celular, o aviso ocupa a linha dele e não separa o Cancelar do botão principal. */
  @media (max-width: 39.9375rem) {
    [role="status"] {
      order: -1;
      flex-basis: 100%;
    }
  }

  /* Desativar e eliminar, longe do Guardar. */
  .a-esquerda {
    margin-right: auto;
  }
}

.cartao {
  background: var(--superficie);
  border: 1px solid var(--linha);
  border-radius: var(--raio-cartao);
}

/* O bloco no fim, longe do resto. */
.separado {
  margin-top: var(--espaco-grande);
  padding-top: var(--espaco-grande);
  border-top: 1px solid var(--linha);
}

/* Pares de rótulo e valor. */
dl {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--espaco-minimo) var(--espaco-medio);
  margin: 0;
  font-size: var(--fonte-pequena);
}

dt {
  color: var(--suave);
}

dd {
  margin: 0;
}

/* Texto secundário. As margens ficam com cada um. */
.suave {
  color: var(--suave);
}

form [role="alert"] {
  margin: 0;
  padding: 0.75rem 0.875rem;
  border-left: 3px solid var(--erro);
  border-radius: 0 var(--raio) var(--raio) 0;
  background: var(--erro-fundo);
  color: var(--erro);
  font-size: var(--fonte-normal);
}

/* O campo na altura do botão. O botão fica à direita também quando quebra para baixo do campo,
   no ecrã estreito. */
.form-em-linha {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  justify-content: end;
  gap: var(--espaco-pequeno);

  > label {
    flex: 1 1 18rem;
  }

  > [role="alert"] {
    flex-basis: 100%;
  }
}

/* O checkbox com o texto ao lado, sem o peso de rótulo de campo. */
.opcao {
  display: flex;
  align-items: center;
  justify-self: start;
  gap: var(--espaco-pequeno);
  font-weight: 400;
}

#aviso {
  position: sticky;
  top: 0;
  z-index: 10;
  margin: 0;
  padding: 0.75rem 1rem;
  background: var(--erro);
  color: #fff;
  text-align: center;
  font-size: var(--fonte-normal);
}

footer {
  text-align: center;
  color: var(--suave);
  font-size: var(--fonte-pequena);
  /* Sem espaço em cima: o de cima do texto é o que o conteúdo já deixa no fim (o main ou a paginação). */
  padding: 0 1rem 1rem;
}

/* Login */

.entrada {
  max-width: 24rem;
  margin: 0 auto;
  padding-top: var(--espaco-grande);
}

:is(.entrada, .documento) .marca {
  font-family: var(--serifa);
  font-style: italic;
  font-size: var(--fonte-subtitulo);
  color: var(--acento);
  margin: 0 0 var(--espaco-grande);
}

.entrada .marca {
  text-align: center;
  margin-bottom: 2.5rem;
}

.entrada form {
  display: grid;
  gap: var(--espaco-grande);
}

.entrada input {
  min-height: 3rem;
  padding: 0.75rem 0.875rem;
  font-size: var(--fonte-normal);
}

.entrada button,
.entrada .botao {
  min-height: 3rem;
  padding: 0.75rem 1.25rem;
  font-size: inherit;
}

.entrada button {
  width: 100%;
  margin-top: var(--espaco-pequeno);
}

.entrada .botao {
  display: flex;
  width: fit-content;
  margin: var(--espaco-grande) auto 0;
}

/* Política de privacidade */

.documento {
  max-width: 36rem;
  margin: 0 auto;
  padding-top: var(--espaco-grande);

  h2 {
    font-size: var(--fonte-subtitulo);
    margin: 2rem 0 0;
  }

  ul {
    padding-left: 1.25rem;
  }

  a {
    color: var(--acento);
  }
}

/* Tabelas: a casca é a `.tabela`; o fundo, a borda e o raio são o `.cartao`. As listas levam também a
   `.enche-a-tela`. */

/* A página fica da altura do ecrã e só a tabela rola, com o cabeçalho sempre à vista. */
body:has(.enche-a-tela) {
  height: 100dvh;
  min-height: 0;
}

main:has(.enche-a-tela) {
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding-bottom: 0;
}

/* Sem a paginação, a tabela encostaria no texto do rodapé: o mesmo respiro que a paginação dá. */
main:has(.enche-a-tela:last-child):has(+ footer:not([hidden])) {
  padding-bottom: var(--espaco-medio);
}

/* O que cada tela pode trocar: especificidade zero. */
:where(.tabela) {
  /* Zebrada, para seguir a linha com os olhos até a última coluna. O `of` só conta as linhas de dados: a
     do formulário, a do detalhe e a do dia não trocam a listra quando abrem. O hover e a encomenda aberta
     pintam por cima. */
  :where(tbody tr:nth-child(even of :not(.edicao, .detalhe, .dia, .sem-linhas)) td) {
    background: var(--listra);
  }

  :where(tbody td) {
    padding: var(--espaco-pequeno) var(--espaco-medio);
  }

  :where(thead th) {
    border-bottom: 1px solid var(--linha);
  }

  /* A informação secundária da linha: a `.nota` embaixo do texto, o `small` ao lado. */
  :where(small, .nota) {
    color: var(--suave);
    font-size: var(--fonte-pequena);
    font-weight: 400;
  }

  :where(.nota) {
    display: block;
  }
}

/* Algarismos da mesma largura, para os números alinharem de uma linha para a outra. */
:where(.tabela, .item, .totais) {
  font-variant-numeric: tabular-nums;
}

/* A faixa à esquerda da linha: a cor do estado no board, o acento na comemoração de hoje. */
:is(.hoje, .board :is(.encomenda, .detalhe)) td:first-child {
  box-shadow: inset 4px 0 0 var(--cor, var(--acento));
}

.divida {
  color: var(--erro);
}

/* O aviso de Hoje / Atrasada, abaixo da data. */
.urgencia {
  display: block;
  color: var(--acento);
  font-size: var(--fonte-minima);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.tabela {
  table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: var(--fonte-normal);
  }

  /* Com o padding fora da escala, o cabeçalho não passa dos 2.25rem do `.enche-a-tela thead th`, de que o `top` do
     `.board .dia th` depende. */
  thead th {
    padding: 0.375rem var(--espaco-medio);
    background: var(--cabecalho);
    color: var(--cabecalho-texto);
    font-size: var(--fonte-pequena);
    font-weight: 600;
    text-align: left;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    white-space: nowrap;
  }

  /* O vazio dentro da tabela, ao contrário do `.vazio`, que fica fora dela. */
  .sem-linhas {
    color: var(--suave);
    text-align: center;
  }

  /* Eliminada a última, só a que avisa da falta fica. */
  tbody:has(> tr:not(.sem-linhas)) > .sem-linhas {
    display: none;
  }
}

/* As cascas da ficha encostam no conteúdo: a linha é a de cima de cada uma, menos a primeira, que
   encosta no cabeçalho, para a última não somar à borda da casca. */
:where(.tabela:not(.enche-a-tela)) :where(tbody tr + tr > td) {
  border-top: 1px solid var(--linha);
}

/* A linha que se abre ao tocar em qualquer ponto dela: o link `.cobre-a-linha` se estica por cima. */
.linha-clicavel {
  position: relative;
  cursor: pointer;
}

.cobre-a-linha {
  color: inherit;
  text-decoration: none;
}

/* Quando abre um diálogo, é botão, mas sem a cara de botão. O `::after` não sai de dentro do botão
   no Firefox: o clique no resto da linha vem do `app.js`. */
button.cobre-a-linha {
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  text-align: inherit;
}

a.cobre-a-linha::after {
  content: "";
  position: absolute;
  inset: 0;
}

/* Mais forte que o `--tingido`, para não se confundir com a listra; o sublinhado diz que o link abre. */
@media (hover: hover) {
  .linha-clicavel:hover td {
    background: color-mix(in srgb, var(--acento) 12%, var(--superficie));
  }

  .linha-clicavel:hover .cobre-a-linha {
    background: none;
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.2em;
  }
}

.enche-a-tela {
  flex: 1;
  min-height: 0;
  margin-top: var(--espaco-medio);
  overflow: auto;
  overscroll-behavior: contain;
}

/* Sticky em cada th e não no thead: no Firefox, o thead fixo deixa o texto das linhas aparecer
   por cima do cabeçalho. Com o Windows a 125% isso ainda acontece, e foi aceito. */
.enche-a-tela thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  height: 2.25rem;
}

/* A tabela é mais alta que as linhas: a linha fecha cada uma, inclusive a última, que não encosta
   na borda da casca. */
.enche-a-tela td {
  border-bottom: 1px solid var(--linha);
  vertical-align: top;
  white-space: nowrap;
}

/* Listas de clientes, de produtos e de utilizadores. Antes da encomenda por causa do noDescendingSpecificity do
   Biome. */

.pesquisa-da-lista {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: end;
  gap: var(--espaco-medio);
  margin-top: var(--espaco-medio);
}

.aviso-da-lista {
  display: flex;
  align-items: center;
  gap: var(--espaco-pequeno);
  margin: var(--espaco-pequeno) 0 0;
}

.pesquisa-da-lista output {
  padding-bottom: var(--espaco-pequeno);
  color: var(--suave);
  font-size: var(--fonte-pequena);
  white-space: nowrap;
}

/* As listas de pouco conteúdo, tão largas como a seção, ficam difíceis de ler: a coluna as estreita,
   com o que as acompanha (pesquisa, avisos, paginação). Em flex, como o main, para a `.enche-a-tela`
   esticar até o fundo. */
.coluna-estreita {
  display: flex;
  flex: 1;
  flex-direction: column;
  width: 100%;
  min-height: 0;
  max-width: 48rem;
  margin-inline: auto;
}

/* Sem o display: contents, a tabela deixaria de ser item flex do pai e de esticar até o fundo. */
#lista {
  display: contents;
}

/* O nome fica com a largura que sobra e quebra; o resto, numa linha. */
.tabela .nome {
  width: 100%;
  font-weight: 600;
  white-space: normal;
}

.tabela .desativado {
  color: var(--suave);
}

/* A coluna fica da largura do conteúdo, numa linha; a sobra vai para as outras. */
.tabela .encolhe {
  width: 1%;
  white-space: nowrap;
}

/* Só nas tabelas: o rótulo do número da porta, na morada, também se chama `.numero`. */
.tabela .numero {
  text-align: right;
}

/* Ao rolar até o criado (`data-mostrar`), o cabeçalho fixo não o cobre. */
.enche-a-tela .linha-clicavel {
  scroll-margin-top: 2.25rem;
}

.paginacao {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--espaco-medio);
  padding: var(--espaco-medio) 0;
  color: var(--suave);
  font-size: var(--fonte-pequena);
}

.paginacao [aria-disabled] {
  opacity: 0.5;
  cursor: default;
}

.dados-do-cliente {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--espaco-pequeno);
  margin-top: var(--espaco-medio);
}

.dados-do-cliente :is(.nome, .email, .indicador, [role="alert"], .botoes) {
  grid-column: 1 / -1;
}

/* O seletor do indicador: o escolhido com o botão de trocar, ou a pesquisa com as sugestões abaixo.
   O `:where` tira a especificidade, para as regras gerais de `.ficha` e `.sugestoes` que vêm depois
   não ficarem por baixo. */
:where(.dados-do-cliente .indicador) {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: var(--espaco-pequeno);

  :is(label, .sugestoes) {
    flex: 1 1 100%;
  }

  p {
    margin: 0;
  }

  .rotulo {
    font-size: var(--fonte-pequena);
    font-weight: 600;
  }
}

:where(.dados-do-cliente .indicador.escolhido) {
  align-items: center;
}

/* O cliente desativado é só para ler: o `fieldset` trava o que está dentro dele sem mexer no
   layout, e o que serviria para alterar some. */
.so-leitura {
  display: contents;
}

.so-leitura:disabled :is(button, .botoes) {
  display: none;
}

/* Os quatro telefones numa linha; NIF, Instagram e e-mail na outra. */
@media (min-width: 40rem) {
  .dados-do-cliente {
    grid-template-columns: repeat(4, 1fr);
  }

  .dados-do-cliente .email {
    grid-column: span 2;
  }
}

/* Encomenda */

/* O título da ficha sem cabeçalho próprio: a encomenda anónima. */
.ficha > h1 {
  margin: var(--espaco-medio) 0 var(--espaco-minimo);
}

/* O título com cabeçalho próprio: na encomenda, o cliente; no cliente, o nome com a ação ao lado. */
:is(.cabecalho, .cabecalho-do-cliente) {
  margin: var(--espaco-medio) 0 var(--espaco-minimo);

  h1 {
    margin: 0;
  }
}

/* O cliente é o título; trocá-lo abre a pesquisa no lugar dele. */
.cabecalho .cliente.escolhido {
  display: flex;
  align-items: center;
  gap: var(--espaco-pequeno);
}

/* Sem espaço, a ação desce e continua à direita. */
.cabecalho-do-cliente {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espaco-pequeno);

  > button {
    margin-left: auto;
  }
}

.ficha .aviso-desativado {
  margin: 0;
}

.cabecalho .cliente h1 a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

.ficha .situacao {
  margin: 0 0 var(--espaco-grande);
}

.dados {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--espaco-pequeno);
  margin-bottom: var(--espaco-grande);
}

.dados
  :is(
    .compromisso,
    .tipo,
    .morada,
    .nova-morada,
    .ocasiao,
    .observacao,
    [role="alert"],
    [role="status"]
  ) {
  grid-column: 1 / -1;
}

.ficha h2 {
  font-size: var(--fonte-subtitulo);
  margin: 0 0 var(--espaco-medio);
}

.ficha h2 .total {
  color: var(--suave);
  font-weight: 400;
}

.itens {
  display: grid;
  gap: var(--espaco-pequeno);
}

/* A coluna do pronto tem largura fixa para a descrição da taxa, que não tem pronto, alinhar com
   a dos produtos. */
.item {
  display: grid;
  grid-template:
    "pronto descricao descricao descricao remover"
    ". quantidade preco subtotal subtotal" / 3rem 3.5rem 5.5rem 1fr 2.25rem;
  align-items: end;
  gap: var(--espaco-pequeno);
  padding: var(--espaco-medio);
}

/* O pronto fica fora do form, e os campos do form entram no mesmo grid que ele. */
.item form {
  display: contents;
}

.item .pronto {
  grid-area: pronto;
}

/* Na altura do campo ao lado, para o check ficar centrado com ele. */
.pronto input {
  margin: var(--espaco-pequeno) 0;
}

.item .descricao {
  grid-area: descricao;
}

.item .quantidade {
  grid-area: quantidade;
}

.item .preco {
  grid-area: preco;
}

.item .subtotal {
  grid-area: subtotal;
  line-height: 2.25rem;
  text-align: right;
  font-weight: 600;
}

.item :is([role="alert"], [role="status"]) {
  grid-column: 1 / -1;
}

/* No diálogo de adicionar item: o tipo, da largura dele, ao lado da descrição; embaixo, a quantidade
   e o preço, os dois da mesma largura, curtos como os da linha do item. Sem a quantidade (a taxa),
   o preço fica no lugar dela. */
.campos-do-item {
  display: grid;
  grid-template-columns: minmax(0, 6.5rem) minmax(0, 6.5rem) minmax(0, 1fr) auto;
  gap: var(--espaco-medio);

  .descricao {
    grid-column: 1 / 4;
  }
}

.sugestoes {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: var(--espaco-pequeno);
}

.sugestoes:empty {
  display: none;
}

.sugestoes button {
  text-align: left;
}

.sugestoes span {
  color: var(--suave);
  font-weight: 400;
}

.sugestoes p {
  flex-basis: 100%;
  margin: 0;
  color: var(--suave);
  font-size: var(--fonte-pequena);
}

.totais {
  display: grid;
  gap: var(--espaco-pequeno);
  margin-top: var(--espaco-grande);
  padding: var(--espaco-medio);
  font-weight: 600;
}

/* Só as linhas da seção: o erro do pago também é um p, e o display venceria o hidden. */
.totais > p {
  display: flex;
  justify-content: space-between;
  margin: 0;
}

.totais form {
  display: grid;
  gap: var(--espaco-pequeno);
}

/* Exceção ao tamanho dos labels: aqui o label é uma linha dos totais, não o rótulo de um campo. */
.totais label {
  grid-template-columns: 1fr 8rem;
  align-items: center;
  font-size: inherit;
}

.totais input {
  text-align: right;
}

.totais [role="status"] {
  font-weight: 400;
}

#divida.devendo {
  color: var(--erro);
}

.desfecho {
  display: grid;
  gap: var(--espaco-medio);
}

/* As ações ficam na ponta direita, como as dos formulários, onde o campo estica até elas. */
.desfecho > button {
  justify-self: end;
}

.desfecho .eliminar {
  display: flex;
  justify-content: end;
}

/* Somada ao `gap`, a mesma separação que a seção tem dos totais. */
.desfecho > .separado {
  margin-top: var(--espaco-medio);
}

.campo-do-cliente {
  display: grid;
  gap: var(--espaco-pequeno);
}

.campo-do-cliente.escolhido {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--espaco-pequeno);
  padding: 0.375rem 0.375rem 0.375rem 0.75rem;
  background: var(--superficie);
  border: 1px solid var(--linha);
  border-radius: var(--raio);
}

.campo-do-cliente.escolhido p {
  margin: 0;
  font-weight: 600;
}

.telemovel {
  color: var(--suave);
  font-weight: 400;
}

/* Nos botões o espaço vem do `gap`. */
p > .telemovel {
  margin-left: var(--espaco-pequeno);
}

/* No cliente escolhido, o telefone fica inteiro: se não couber ao lado do nome, passa para a linha
   seguinte, sem o espaço que o separava do nome. */
.campo-do-cliente.escolhido .telemovel {
  white-space: nowrap;
  margin-left: 0;
}

.cadastro {
  display: grid;
  gap: var(--espaco-pequeno);
  margin: 0;
  padding: var(--espaco-medio);
  border: 1px solid var(--linha);
  border-radius: var(--raio);
}

.cadastro legend {
  padding: 0 var(--espaco-minimo);
  color: var(--suave);
  font-size: var(--fonte-pequena);
}

.cadastro .botoes {
  justify-content: flex-start;
}

.cadastro .aviso-do-telemovel {
  margin: 0;
  font-size: var(--fonte-pequena);
}

/* Fechado, não ocupa linha no grid dos dados. */
.nova-morada:empty {
  display: none;
}

.nova-morada .cadastro p {
  margin: 0;
  font-size: var(--fonte-pequena);
}

/* O Cancelar da pesquisa, que desiste da troca. */
#manter-cliente {
  justify-self: start;
}

.dialogo {
  width: min(32rem, 100% - 2rem);
  padding: var(--espaco-grande);
  color: inherit;

  &::backdrop {
    background: color-mix(in srgb, var(--texto) 35%, transparent);
  }

  form {
    display: grid;
    gap: var(--espaco-medio);
  }

  /* Dia, mês e ano lado a lado mesmo no telemóvel; o resto ocupa a linha toda. O dia cabe em dois
     algarismos e o ano no "Opcional": a sobra vai para o nome do mês. */
  &:where(.com-data) form {
    grid-template-columns: 3.5rem 1fr 6rem;
  }

  &:where(.com-data) form > :is(:not(label), .descricao, .observacao) {
    grid-column: 1 / -1;
  }

  /* A data e a origem, quando houver largura; o resto ocupa a linha toda. */
  &:where(.com-data-e-origem) form > :not(.compromisso, .origem) {
    grid-column: 1 / -1;
  }

  /* A morada e a referência ocupam a linha; o resto, dois a dois. O `fieldset` da desativada não tem
     caixa: os campos dela entram na grelha. */
  &:where(.com-morada) form {
    grid-template-columns: 1fr 1fr;
  }

  &:where(.com-morada) form > :not(label, fieldset),
  &:where(.com-morada) form .referencia,
  &:where(.com-morada) form .rua {
    grid-column: 1 / -1;
  }

  h2 {
    margin: 0;
    font-size: var(--fonte-subtitulo);
  }

  /* Colada ao campo do cliente, de que fala, e do tamanho do rótulo dele. */
  .dica {
    margin: -0.5rem 0 0;
    font-size: var(--fonte-pequena);
  }

  /* No lugar da data, que não muda pela tela. */
  .regra {
    margin: 0;
  }
}

@media (min-width: 40rem) {
  .dados {
    grid-template-columns: repeat(3, 1fr);
  }

  .dados :is(.compromisso, .tipo, .morada, .ocasiao) {
    grid-column: auto;
  }

  .item {
    grid-template: "pronto descricao quantidade preco subtotal remover" / 3rem 1fr 4rem 6.5rem 6rem 2.25rem;
  }

  .dialogo:where(.com-data-e-origem) form {
    grid-template-columns: 1fr 1fr;
  }

  /* Morada e número numa linha; complemento, código postal e localidade na outra. */
  :is(.nova-morada .cadastro, .dialogo:where(.com-morada) form) {
    grid-template-columns: repeat(3, 1fr);
  }

  .nova-morada .cadastro > :not(.rua, .numero, .complemento, .codigo-postal, .localidade) {
    grid-column: 1 / -1;
  }

  :is(.nova-morada, .dialogo:where(.com-morada) form) .rua {
    grid-column: span 2;
  }
}

/* Botão quadrado só com o ícone, com o círculo de espera no meio dele. */
.so-icone {
  flex: none;
  width: 2.25rem;
  padding: 0;
}

.so-icone.carrega::before {
  left: calc(50% - 0.5625rem);
}

.item .so-icone {
  grid-area: remover;
}

/* Menor, para a linha da tabela ficar da altura de uma de texto e para o botão ao lado de um título. */
.so-icone.pequeno {
  width: 1.75rem;
  min-height: 1.75rem;
  height: 1.75rem;

  .icone {
    width: 1rem;
    height: 1rem;
  }
}

/* Título de seção da ficha com o botão de ícone ao lado. */
.ficha .titulo {
  display: flex;
  align-items: center;
  gap: var(--espaco-pequeno);

  /* O `.ficha h2` tem margem embaixo, que descentraria o título do botão. */
  h2 {
    margin: 0;
    line-height: 1.75rem;
  }
}

/* A margem que o `h2` perdeu, longe da lista dos itens. */
.secao-dos-itens > .titulo {
  margin-bottom: var(--espaco-medio);
}

.secao-da-ficha {
  margin-top: var(--espaco-grande);
  display: grid;
  gap: var(--espaco-pequeno);

  .tabela {
    overflow-x: auto;
  }

  td {
    vertical-align: middle;
  }
}

/* A de utilizadores, editada no lugar: a linha `.edicao` guarda o formulário, escondido, e o `app.js` a abre. */

.utilizadores {
  td {
    vertical-align: middle;
  }

  /* A margem do `scrollIntoView` do `app.js`: a linha aberta não fica colada no fundo da janela. */
  .edicao {
    scroll-margin-bottom: 1.5rem;
  }

  th.acoes {
    text-align: right;
  }

  /* Com o botão `.pequeno`, o padding menor deixa a linha da altura de uma de texto. */
  td.acoes {
    padding-block: var(--espaco-minimo);
    text-align: right;
  }

  /* A `.enche-a-tela` não quebra o texto das linhas; o formulário precisa. */
  .edicao > td {
    white-space: normal;
  }

  form {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--espaco-pequeno);
  }

  form :is([role="alert"], .botoes) {
    grid-column: 1 / -1;
  }

  .admin {
    grid-column: 1 / -1;
  }
}

/* A palavra-passe e o botão de copiar não se separam na quebra de linha. Depois de copiar, o
   botão mostra o visto no lugar do ícone de copiar. */
.aviso-da-lista .senha {
  display: inline-flex;
  align-items: center;
  gap: var(--espaco-minimo);
  white-space: nowrap;

  code {
    color: var(--texto);
    font-weight: 600;
  }

  button:not([data-copiado]) .icone:last-child,
  button[data-copiado] .icone:first-child {
    display: none;
  }
}

.moradas {
  .principal {
    text-align: center;
  }

  .desativada .endereco {
    color: var(--suave);
  }
}

/* A principal, travada, segue marrom (mais claro, como o botão primário desabilitado) e não cinza:
   marcada ela se destaca, e o claro diz que não se desmarca. */
.moradas .principal input:disabled {
  appearance: none;
  border: 1px solid var(--tingido-borda);
  border-radius: 4px;
  background: var(--tingido);
  cursor: not-allowed;
}

.moradas .principal input:disabled:checked {
  border-color: transparent;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-7' fill='none' stroke='%23fffaf3' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")
    center / 0.875rem no-repeat,
    color-mix(in srgb, var(--acento) 60%, var(--superficie));
}

/* Próximas comemorações */

.periodo {
  margin: var(--espaco-medio) 0 0;
}

.proximas-comemoracoes {
  td:is(.data, .descricao) {
    vertical-align: middle;
  }

  time {
    font-weight: 600;
  }

  td.descricao {
    width: 100%;
    font-weight: 600;
    white-space: normal;
  }

  /* Em flex, o link fica do tamanho do nome, e não da célula. */
  .cliente {
    display: flex;
    align-items: center;
    gap: var(--espaco-pequeno);
    font-weight: 400;
  }
}

/* Board */

/* As margens negativas anulam o padding do main e do body: a barra encosta no topo, por baixo do entalhe. */
.topo {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: var(--espaco-pequeno);
  margin: calc(-1.5rem - env(safe-area-inset-top)) -1.25rem 0;
  padding: calc(0.5rem + env(safe-area-inset-top)) 1.25rem 0.5rem;
  background: color-mix(in srgb, var(--fundo) 88%, transparent);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--linha);
}

.topo h1 {
  font-size: var(--fonte-titulo);
  margin: 0;
}

.filtros {
  margin-top: var(--espaco-medio);
}

.filtros summary {
  display: flex;
  align-items: center;
  gap: var(--espaco-pequeno);
  min-height: 2.75rem;
  padding: 0.5rem 0.875rem;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}

.filtros summary::-webkit-details-marker {
  display: none;
}

.filtros summary::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  margin-right: var(--espaco-minimo);
  border: solid var(--suave);
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(-45deg);
  transition: transform 0.15s;
}

.filtros[open] summary::before {
  transform: rotate(45deg);
}

#contagem {
  display: flex;
  flex: 1;
  align-items: baseline;
  gap: var(--espaco-medio);
  font-weight: 400;
  font-size: var(--fonte-normal);
}

#contagem .ativos {
  padding: 0 var(--espaco-pequeno);
  border-radius: 999px;
  background: color-mix(in srgb, var(--acento) 12%, transparent);
  color: var(--acento);
  font-size: var(--fonte-pequena);
  font-weight: 600;
}

#contagem output {
  margin-left: auto;
  color: var(--suave);
}

.filtros form {
  display: grid;
  grid-template: "pesquisa pesquisa" "de ate" "atalhos atalhos" "ver ver" / 1fr 1fr;
  gap: var(--espaco-medio);
  padding: 0.125rem 0.875rem 0.75rem;
}

.filtros .pesquisa {
  grid-area: pesquisa;
}

.filtros .de {
  grid-area: de;
}

.filtros .ate {
  grid-area: ate;
}

.filtros .atalhos {
  grid-area: atalhos;
}

/* O checkbox das Comemorações ocupa a área dos chips do board. */
.filtros .incluir {
  grid-area: ver;
}

.filtros .ver {
  position: relative;
  grid-area: ver;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

/* Os chips se explicam; a legenda fica só para o leitor de ecrã. */
.filtros legend {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* No celular, uma faixa que rola para o lado em vez de quebrar em várias linhas. As margens
   negativas levam a faixa até a borda do painel, e o padding vertical dá espaço ao contorno do foco. */
.filtros .atalhos,
.filtros .faixa {
  display: flex;
  gap: var(--espaco-pequeno);
  margin: -0.3125rem -0.875rem;
  padding: 0.3125rem 0.875rem;
  overflow-x: auto;
  scrollbar-width: none;
}

/* Setas sobre a faixa enquanto há chips escondidos daquele lado (o app.js marca o lado). Em SVG
   e não "‹ ›": o caractere fica na altura da minúscula e parece baixo ao lado do chip. */
.filtros .ver::before,
.filtros .ver::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  z-index: 1;
  width: 2.75rem;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s;
}

.filtros .ver::before {
  left: -0.875rem;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='14'%3E%3Cpath d='M7 1L1 7l6 6' fill='none' stroke='%237b3f22' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")
    no-repeat left 0.75rem center,
    linear-gradient(to left, transparent, var(--superficie) 55%);
}

.filtros .ver::after {
  right: -0.875rem;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='14'%3E%3Cpath d='M1 1l6 6-6 6' fill='none' stroke='%237b3f22' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")
    no-repeat right 0.75rem center,
    linear-gradient(to right, transparent, var(--superficie) 55%);
}

.filtros .ver[data-antes]::before,
.filtros .ver[data-depois]::after {
  opacity: 1;
}

.filtros .chip {
  position: relative;
  display: flex;
  flex-shrink: 0;
  align-items: center;
  min-height: 2.25rem;
  padding: 0.25rem 0.75rem;
  border: 1px solid var(--linha);
  border-radius: 999px;
  background: transparent;
  color: var(--texto);
  font-size: var(--fonte-pequena);
  font-weight: 400;
  white-space: nowrap;
  cursor: pointer;
}

/* Rádio escondido: o chip inteiro é o alvo do toque. */
.filtros .chip input {
  position: absolute;
  opacity: 0;
  width: 1px;
  min-height: 0;
  height: 1px;
  pointer-events: none;
}

.filtros .chip:has(:checked) {
  border-color: var(--acento);
  background: color-mix(in srgb, var(--acento) 12%, var(--superficie));
  color: var(--acento);
  font-weight: 600;
}

@media (min-width: 52rem) {
  .filtros form {
    grid-template: "pesquisa de ate" ". atalhos atalhos" "ver ver ver" / 2fr 1fr 1fr;
  }

  .filtros .atalhos,
  .filtros .faixa {
    flex-wrap: wrap;
    margin: 0;
    padding: 0;
    overflow: visible;
  }
}

/* Só a partir daqui os atalhos cabem na linha das datas sem espremê-las. */
@media (min-width: 64rem) {
  .filtros form {
    grid-template: "pesquisa de ate atalhos" "ver ver ver ver" / 2fr 1fr 1fr auto;
  }

  .filtros .atalhos {
    align-self: end;
  }
}

/* Sem o display: contents, a .board deixaria de ser filha do main e de esticar até o fundo. */
#encomendas {
  display: contents;
}

/* Fixa logo abaixo do cabeçalho (a altura dele); o dia seguinte, ao chegar, empurra este. */
.board .dia th {
  position: sticky;
  top: 2.25rem;
  z-index: 1;
  padding: var(--espaco-medio) var(--espaco-medio) var(--espaco-pequeno);
  background: var(--subcabecalho);
  border-bottom: 1px solid var(--linha);
  color: var(--cabecalho-texto);
  font-size: var(--fonte-pequena);
  font-weight: 600;
  text-align: left;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.board .detalhe {
  cursor: pointer;
}

.board time {
  font-weight: 600;
}

.board .cliente {
  font-weight: 600;
  white-space: normal;
}

/* Uma linha só; o texto inteiro aparece ao tocar na encomenda. */
.board .resumo,
.board .estreito {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.board .resumo {
  max-width: 22rem;
}

.estado::before {
  content: "";
  display: inline-block;
  width: 0.625rem;
  height: 0.625rem;
  margin-right: var(--espaco-pequeno);
  border-radius: 50%;
  background: var(--cor);
}

/* O detalhe continua a encomenda de cima: sem o respiro em cima. */
.board .detalhe td {
  padding-top: 0;
  white-space: normal;
}

/* Aberta, a encomenda e o detalhe viram um bloco só, tingido com a cor do estado, para não se
   confundirem com a linha do dia. */
.board .detalhe td,
.board .encomenda:has(+ .detalhe:not([hidden])) td {
  background: color-mix(in srgb, var(--cor) 10%, var(--superficie));
}

/* Sem a linha entre a encomenda e o detalhe. */
.board .encomenda:has(+ .detalhe:not([hidden])) td {
  border-bottom: 0;
}

/* Debaixo da hora, com o ícone por cima do texto para caberem na coluna estreita. */
.board .botoes-curtos {
  display: grid;
  gap: var(--espaco-pequeno);
}

.board .botoes-curtos > * {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.125rem;
  min-height: 2.75rem;
  padding: 0.375rem 0.5rem;
  background: var(--superficie);
  font-size: var(--fonte-minima);
  line-height: 1.2;
  text-align: center;
}

/* Aqui o ícone vai centrado em cima do texto. */
.board .botoes-curtos .carrega::before {
  top: 0.375rem;
  left: calc(50% - 0.5625rem);
}

.board .acoes {
  display: grid;
  gap: var(--espaco-pequeno);
  margin-top: var(--espaco-medio);
}

/* Aqui o campo não estica, e o botão fica logo ao lado dele. */
.board .form-em-linha {
  justify-content: start;

  > label {
    flex-grow: 0;
  }
}

@media (max-width: 52rem) {
  .board .largo {
    display: none;
  }

  .board td {
    padding: var(--espaco-pequeno);
  }

  /* O cliente fica com a largura que sobra; sem o max-width o resumo alargaria a tabela. */
  .board .cliente {
    width: 100%;
    max-width: 0;
  }

  /* Quebra só entre "em dívida" e o valor: os dois têm espaço inseparável por dentro. */
  .board .divida {
    white-space: normal;
  }
}

@media (min-width: 52rem) {
  .board .estreito {
    display: none;
  }
}

/* Só a admin a vê. */
.ficha .rgpd {
  display: grid;
  gap: var(--espaco-medio);

  > :is(h2, p) {
    margin: 0;
  }

  > p a {
    color: inherit;
  }

  > .exportar {
    justify-self: start;
  }
}

/* Encomendas da ficha. Depois do board e sem seletores soltos de `td`, que o noDescendingSpecificity
   do Biome compara com os dele. */

/* O título e o cabeçalho da tabela ficam fixos logo abaixo da barra de topo (a altura dela), e a
   paginação rola até a tabela nova sem escondê-la por baixo deles. */
.encomendas-do-cliente {
  --titulo: 2.75rem;
  margin-top: var(--espaco-medio);

  > .titulo {
    position: sticky;
    top: var(--altura-topo);
    z-index: 2;
    height: var(--titulo);
    padding: var(--espaco-pequeno) 0 var(--espaco-medio);
    background: var(--fundo);
  }

  /* Fixo, o cabeçalho da tabela deixa para cima os cantos arredondados do contorno: os dois
     gradientes, presos ao título, os redesenham por cima dele. Parados, coincidem com os da tabela. */
  > .titulo::after {
    --r: var(--raio-cartao);
    --canto:
      transparent calc(var(--r) - 1px), var(--linha) calc(var(--r) - 1px) var(--r),
      var(--fundo) var(--r);
    content: "";
    position: absolute;
    top: 100%;
    inset-inline: 0;
    height: var(--r);
    background:
      radial-gradient(circle at 100% 100%, var(--canto)) left / var(--r) var(--r) no-repeat,
      radial-gradient(circle at 0 100%, var(--canto)) right / var(--r) var(--r) no-repeat;
    pointer-events: none;
  }

  #encomendas-da-ficha {
    scroll-margin-top: calc(var(--altura-topo) + var(--titulo));
  }

  /* Clip e não auto: uma área de rolagem prenderia o cabeçalho fixo dentro dela, longe da rolagem
     da página. Abaixo de 360px a tabela não cabe: rola para o lado, sem cabeçalho fixo. */
  .tabela {
    overflow: clip;
    border-top: 0;
  }

  @media (max-width: 22.4375rem) {
    .tabela {
      overflow-x: auto;
    }
  }

  tbody tr {
    vertical-align: top;
  }

  td.compromisso a {
    font-weight: 600;
  }

  /* Sem a quebra antes do valor em dívida, a tabela não cabe no telemóvel, e o clip cortaria o
     total. */
  @media (max-width: 30rem) {
    .divida {
      white-space: normal;
    }
  }
}

/* Fora do aninhamento: o Biome não soma o pai na especificidade e o compararia com o
   `.board .dia th`. A casca não tem borda em cima (o título desenha os cantos): a linha de cima é
   a do th fixo, para não ficar para trás. */
.encomendas-do-cliente .tabela thead th {
  position: sticky;
  top: calc(var(--altura-topo) + var(--titulo));
  z-index: 1;
  border-top: 1px solid var(--linha);
}

/* Caminho e utilizador */

.caminho {
  min-width: 0;
}

.caminho ol {
  display: flex;
  align-items: center;
  gap: var(--espaco-pequeno);
  margin: 0;
  padding: 0;
  list-style: none;
}

.caminho > ol > li {
  display: flex;
  align-items: center;
  min-width: 0;
}

/* Desenhado, e não o "›": o caractere fica na linha de base e desce ao lado do h1. */
.caminho > ol > li + li::before {
  content: "";
  flex: none;
  width: 6px;
  height: 10px;
  margin-right: var(--espaco-pequeno);
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='6' height='10'%3E%3Cpath d='M1 1l4 4-4 4' fill='none' stroke='%237a6656' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.caminho > ol > li[aria-current] {
  color: var(--suave);
}

/* Num elemento próprio: o texto solto no flex vira item anónimo, e o ellipsis não pega. */
.caminho > ol > li > :is(span, h1) {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.caminho h1 {
  color: var(--texto);
}

.topo .caminho > ol > li > a {
  display: flex;
  align-items: center;
  min-height: 2.25rem;
  font-weight: 600;
  color: var(--acento);
  text-decoration: none;
}

/* Aberto, o painel cai por cima da página. */
.menu {
  position: relative;
}

/* O realce do aberto e do hover. */
.menu summary {
  --realce-borda: var(--tingido-borda);
  --realce-fundo: var(--tingido);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  min-height: 2.25rem;
  list-style: none;
  cursor: pointer;
  border: 1px solid transparent;
  border-radius: var(--raio);
}

.menu summary::-webkit-details-marker {
  display: none;
}

/* A margem negativa alinha a casa, e não a borda do botão, ao conteúdo. Tingida em repouso como a conta, mas quadrada. */
.secoes summary {
  --realce-borda: var(--acento);
  --realce-fundo: color-mix(in srgb, var(--acento) 16%, var(--superficie));
  margin-left: -0.5625rem;
  border-color: var(--tingido-borda);
  background: var(--tingido);
  color: var(--acento);
}

.conta {
  margin-left: auto;
}

/* Tingido já em repouso: o realce carrega mais no tom. */
.conta summary {
  --realce-borda: var(--acento);
  --realce-fundo: color-mix(in srgb, var(--acento) 16%, var(--superficie));
  border-color: var(--tingido-borda);
  border-radius: 50%;
  background: var(--tingido);
  font-size: var(--fonte-pequena);
  font-weight: 600;
  color: var(--acento);
}

.menu[open] summary {
  border-color: var(--realce-borda);
  background: var(--realce-fundo);
}

@media (hover: hover) {
  .menu summary:hover {
    border-color: var(--realce-borda);
    background: var(--realce-fundo);
  }
}

.menu .painel {
  position: absolute;
  top: calc(100% + 0.375rem);
  display: grid;
  /* Absoluto, a largura viria do botão, e o texto quebraria. Cabe na tela, com a margem do topo. */
  width: max-content;
  min-width: 11rem;
  max-width: calc(100vw - 2.5rem);
  margin: 0;
  padding: var(--espaco-pequeno);
  list-style: none;
  box-shadow: 0 8px 24px color-mix(in srgb, var(--texto) 12%, transparent);
}

.secoes .painel {
  left: 0;
}

.conta .painel {
  right: 0;
}

.menu .secundario {
  width: 100%;
  justify-content: flex-start;
  min-height: 2.75rem;
  border: 0;
  font-size: var(--fonte-normal);
  font-weight: 400;
  color: var(--texto);
}

/* Antes das seções de admin. */
.secoes [role="separator"] {
  margin: var(--espaco-pequeno) 0;
  border-top: 1px solid var(--linha);
}

.secoes [aria-current] {
  font-weight: 600;
  color: var(--acento);
  position: relative;
}

/* Fora do item, no respiro do painel, e mais baixa que ele. */
.secoes [aria-current]::after {
  content: "";
  position: absolute;
  top: 25%;
  bottom: 25%;
  left: calc(-0.375rem + 1px);
  width: 4px;
  border-radius: 2px;
  background: var(--acento);
}

.topo .conta p {
  margin: 0;
  padding: 0.5rem 0.875rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--suave);
}

/* Separado do nome: é uma ação, não informação. */
.conta .sair {
  border-top: 1px solid var(--linha);
  border-radius: 0 0 var(--raio) var(--raio);
}

.vazio {
  color: var(--suave);
  text-align: center;
  margin-top: 3rem;
}
