:root {
  --ink-950: #0d1420;
  --ink-900: #131c2b;
  --ink-700: #2c3850;
  --paper: #f7f5ef;
  --paper-soft: #fbfaf6;
  --card: #ffffff;
  --line: #e7e1d3;
  --line-strong: #d8d0be;

  --green: #0e8a5e;
  --green-dark: #0a6f4c;
  --green-soft: #e6f4ee;
  --gold: #c99b2a;
  --gold-dark: #a37c1c;
  --gold-soft: #f8f1dc;

  --muted: #5d6775;
  --muted-light: #8a93a0;
  --red: #b42318;
  --wa: #22c15a;
  --wa-dark: #1da851;

  --font-display: "Sora", "Inter", system-ui, sans-serif;
  --font-body: "Inter", system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, monospace;

  --radius: 14px;
  --radius-sm: 9px;
  --shadow: 0 1px 2px rgba(13, 20, 32, 0.06), 0 14px 40px -26px rgba(13, 20, 32, 0.28);
  --shadow-lift: 0 18px 46px -24px rgba(13, 20, 32, 0.4);
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

/* Proteção de imagens: sem gravar por botão direito, arrastar ou toque prolongado */
img {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-user-drag: none;
}

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--ink-900);
  background: var(--paper);
  line-height: 1.55;
  font-size: 15.5px;
  -webkit-font-smoothing: antialiased;
}
html, body { overflow-x: clip; }

.container { max-width: 1060px; margin: 0 auto; padding: 0 22px; }

/* Campo de ficheiro escondido mas VIVO. `hidden`/`display:none` tira o campo da
   ordem de tabulação, e um `<label for>` não é focável por si: o botão
   «Importar de um CV antigo» (o caminho recomendado) ficava inalcançável por teclado.
   `.sr-only` esconde sem tirar do fluxo de foco. Ver `input[type=file]:focus-visible`
   abaixo — o foco tem de aparecer no rótulo que substitui o campo. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
input[type="file"].sr-only:focus-visible + label { outline: 2px solid var(--green); outline-offset: 3px; }
/* `.field input` é (0,1,1) e ganhava ao `.sr-only` (0,1,0): o input de ficheiro
   da fotografia ficava com 100% de largura a partir da sua posição estática —
   46px de página a mais, que no telemóvel se arrastavam para a direita e não
   voltavam (o gesto para a esquerda só «recuperava» porque não havia nada à
   esquerda). O `sr-only` tem de ganhar em qualquer sítio onde caia. */
.field input.sr-only,
.field .sr-only {
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
}

/* ---------- Header ---------- */
.site-header {
  background: var(--paper-soft);
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 30;
}
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 62px;
  gap: 14px;
}
.brand {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -0.5px;
  color: var(--ink-950);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 2px;
  /* A marca é a única peça da barra que pode ceder: os ícones e o hambúrguer têm
     tamanho fixo, logo sem isto, abaixo de ~290px de viewport a barra estourava e o
     `overflow-x: clip` levava o botão do menu com ela (medido a 280px: o botão
     acabava em 288.3, 8.3px fora do ecrã). O logo encolhe e é o que se corta. */
  min-width: 0;
  overflow: hidden;
}
.brand-hi { color: var(--green); }
.brand-tld { color: var(--muted-light); font-weight: 600; letter-spacing: 0; }
.brand img { height: 38px; width: auto; display: block; }
@media (max-width: 560px) { .brand img { height: 30px; } }
.header-right { display: flex; align-items: center; gap: 16px; }
/* A barra de navegação é uma fila encostada à direita: `flex: 1` para ocupar o
   espaço entre a marca e o fim do header, `justify-content: flex-end` para a
   fila ir para a direita (o «Iniciar Sessão» é o primeiro dela, e é o ÚNICO na
   entrada sem sessão — ali só há ele e o botão largo; ver `nav_sem_atalhos`). */
.header-right { display: flex; align-items: center; gap: 16px; flex: 1; justify-content: flex-end; }
.nav-toggle {
  display: none;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 10px;
  background: none;
  color: var(--ink-900);
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex: 0 0 auto;
  /* Sem quadrado: só as 3 linhas do ícone, à altura do botão «Começar» ao
     lado (o quadrado de 40px ao lado de um btn-sm de 27px parecia de outro
     sítio — o ícone é o botão). O toque continua a ter 40px de alvo. */
  padding: 0;
}
.nav-toggle svg { width: 24px; height: 24px; }
/* Dois ícones no mesmo botão: o menu (3 linhas) e o X. O X só se mostra
   quando o painel está aberto — o `.open` vive no nav, e o botão é irmão
   dele dentro do `.header-inner`. */
.nav-toggle .ico-x { display: none; }
.header-inner.nav-collapsed .site-nav.open ~ .nav-toggle .ico-menu,
.header-inner.mobile-hamburguer .site-nav.open ~ .nav-toggle .ico-menu,
.header-inner.landing-mobile .site-nav.open ~ .nav-toggle .ico-menu { display: none; }
.header-inner.nav-collapsed .site-nav.open ~ .nav-toggle .ico-x,
.header-inner.mobile-hamburguer .site-nav.open ~ .nav-toggle .ico-x,
.header-inner.landing-mobile .site-nav.open ~ .nav-toggle .ico-x { display: block; }
/* Na landing mobile o hambúrguer encosta ao «Começar»: mesma altura que ele
   (27px), com o ícone a 22px — as duas peças da direita leem-se como uma. */
@media (max-width: 760px) {
  .header-inner.landing-mobile .nav-toggle { height: 27px; }
  .header-inner.landing-mobile .nav-toggle svg { width: 22px; height: 22px; }
}
/* Menu que não cabe → hambúrguer. Quem põe `nav-collapsed` no cabeçalho é o guião, a
   partir da medida da barra (ver o guião no `base.html`): um menu de 3 itens cabe a
   500px e um de 6 não cabe aos 1000, por isso um breakpoint fixo errava sempre num dos
   lados. As regras do painel são as do `@media` dos 760px — que fica como o caso sem
   JavaScript — mas valem a qualquer largura. */
.header-inner.nav-collapsed .nav-toggle { display: inline-flex; }
.header-inner.nav-collapsed .site-nav { display: none; }
.header-inner.nav-collapsed .site-nav.open {
  display: flex;
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--paper-soft);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 24px 40px -24px rgba(13, 20, 32, 0.35);
  padding: 10px 22px 16px;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
  z-index: 40;
  /* A lista pode ser mais alta do que o ecrã (a gestão tem o índice todo lá dentro): o scroll é
     dela, não o da página — senão os últimos itens saem pelo fundo fora e o polegar não lá chega. */
  max-height: calc(100vh - 72px);
  max-height: calc(100dvh - 72px);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.header-inner.nav-collapsed .site-nav.open .link,
.header-inner.nav-collapsed .site-nav.open .muted-link {
  display: block;
  padding: 11px 6px;
  font-size: 14.5px;
  border-bottom: 1px solid var(--line);
  text-align: left;
}
/* No painel o item é uma linha «ícone + texto» à ESQUERDA, com o espaço que sobra à
   direita vazio (não centrado: a linha inteira é o alvo do toque). O .head-item leva
   também .link, cujo display:block (0,3,0) vence o inline-flex (0,1,0) — daí o
   display:flex AQUI, com a mesma especificidade da regra que o desfaz. */
.header-inner.nav-collapsed .site-nav.open .head-item {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-start; /* dentro do painel nav-icons, o center do @media vencia — o conteúdo ia para o meio da linha */
  gap: 10px;
  width: auto;
  height: auto;
}
.header-inner.nav-collapsed .site-nav.open .nav-label { font-size: 14.5px; }
.header-inner.nav-collapsed .site-nav.open .btn { display: flex; margin-top: 8px; width: 100%; }
/* O «Iniciar Sessão» é o PRIMEIRO item da barra, mas no painel volta ao fim: o
   DOM segue a ordem da barra (que é a do desktop, e é a que o teclado percorre)
   e quem reordena é o `order` — só dentro do painel, senão o botão ia para o fim
   da barra do desktop também. O botão largo fica depois dele, para os dois
   continuarem emparelhados no fundo. */
.header-inner.nav-collapsed .site-nav.open .btn-entrar { order: 1; }
.header-inner.nav-collapsed .site-nav.open .btn-primary { order: 2; }
/* O mesmo no painel que o guião abre por MEDIDA (o outro hambúrguer): o submenu
   dos dropdowns vem ESTÁTICO, com os itens indentados — o de base é `absolute`
   e, no painel, flutuava por cima das linhas de baixo.

   O `display` NÃO é forçado a `block`: quem manda é a classe `.open`, que o
   guião alterna. Forçá-lo abria todos os grupos de uma vez e o toque no gatilho
   não fazia nada (o submenu já estava à vista) — o painel parecia morto. Agora
   é acordeão: tocar abre o grupo (e fecha os outros), tocar outra vez fecha. */
.header-inner.nav-collapsed .site-nav.open .head-dropdown {
  display: flex;
  flex-direction: column;
  width: 100%;
}
.header-inner.nav-collapsed .site-nav.open .head-dropdown-menu {
  position: static;
  min-width: 0;
  background: none;
  border: 0;
  box-shadow: none;
  padding: 0 0 0 18px;
}
.header-inner.nav-collapsed .site-nav.open .head-dropdown-menu .link {
  padding: 10px 6px;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
}
/* O par «Novo» + «Painel» que a ENTRADA põe no mobile depois de escolhido o
   produto (ver `nav-mobile-produto` em base.html). Fora do mobile nunca se vê:
   aí a entrada é o «Documentos» centralizado com o botão largo ao lado. */
.nav-mobile-produto { display: none; }

.site-nav { display: contents; }
.head-item { display: inline-flex; align-items: center; gap: 7px; position: relative; }
.head-item svg { width: 15px; height: 15px; flex: 0 0 auto; }
.head-ico { position: relative; display: inline-flex; }
.aff-badge {
  position: absolute;
  top: -3px;
  right: -3px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--green);
  border: 2px solid var(--paper-soft);
  pointer-events: none;
}
.head-item.is-active { text-decoration: underline; text-underline-offset: 5px; color: var(--green-dark); }
.head-dropdown { position: relative; display: inline-flex; }
.head-dropdown > .link {
  border: 0;
  background: none;
  padding: 0;
  font-family: inherit;
  line-height: inherit;
  cursor: pointer;
  appearance: none;
}
.head-dropdown-menu {
  display: none;
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  min-width: 190px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 18px 46px -24px rgba(13, 20, 32, 0.4), 0 1px 2px rgba(13, 20, 32, 0.08);
  padding: 6px;
  z-index: 50;
}
.head-dropdown-menu.open { display: block; }
.head-dropdown-menu .link {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-radius: 8px;
  text-decoration: none;
  font-weight: 600;
  font-size: 14px;
}
.head-dropdown-menu .link svg { width: 16px; height: 16px; flex: 0 0 auto; }
.head-dropdown-menu .link:hover { background: var(--green-soft); color: var(--green-dark); text-decoration: none; }
/* O produto escolhido no submenu «Documentos» (a classe é do servidor, vem do
   `?f=` em core/views.py). O hover pinta EXACTAMENTE o mesmo verde, por isso o
   que diz «este é que está escolhido» é o VISTO — um fundo verde sozinho
   lia-se como o rato por cima. O visto só existe no item marcado (display:none
   por omissão) para não pesar as duas linhas. */
.head-dropdown-menu .link .ico-check { display: none; }
.head-dropdown-menu .link.is-active { background: var(--green-soft); color: var(--green-dark); }
.head-dropdown-menu .link.is-active .ico-check { display: block; margin-left: auto; }
/* O caret do «Documentos» roda quando o submenu está aberto — também no
   desktop, onde o submenu pode abrir-se sozinho (há produto escolhido). */
.head-dropdown:has(.caret) .caret { transition: transform 0.15s ease; }
.head-dropdown:has(.head-dropdown-menu.open) .caret { transform: rotate(180deg); }

/* Selector de idioma do cabeçalho (ver partials/lang_switch.html). Reutiliza o
   `.head-dropdown`; só o menu é mais estreito (duas opções curtas) e a opção
   activa é um <span> — não navega, por isso o cursor não é pointer. */
.head-lang-menu { min-width: 150px; }
.head-lang-menu .link.is-active { cursor: default; }

@media (max-width: 760px) {
  /* Só quando o menu é uma LISTA DE TEXTO (a gestão, `.nav-drop`): é esse que não cabe.
     Na barra de ícones os itens cabem todos à vista, e um hambúrguer ao lado deles
     aparecia «sem necessidade». Nas páginas públicas quem decide é a medida, no
     guião — aqui é o caso sem JavaScript. */
  .site-nav.nav-drop ~ .nav-toggle { display: inline-flex; }
  .header-inner { height: 58px; gap: 10px; }
  .header-right { gap: 8px; }
  .site-nav { display: none; }

  .site-nav.nav-drop {
    position: absolute;
    top: 58px;
    left: 0;
    right: 0;
    background: var(--paper-soft);
    border-bottom: 1px solid var(--line);
    box-shadow: 0 24px 40px -24px rgba(13, 20, 32, 0.35);
    padding: 10px 22px 16px;
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    z-index: 40;
  }
  .site-nav.nav-drop.open { display: flex; }

  /* O submenu vem ESTATICO e indentado no painel. O de base e `absolute`, e no
     painel flutuava por cima das linhas de baixo. A copia do `.nav-collapsed`
     ja o fazia; esta — a do caso sem JavaScript, que e a que serve os ecraes
     abaixo dos 760px — tinha ficado sem estas regras.

     Como no `.nav-collapsed`, o `display` nao e forcado: cada grupo abre e
     fecha pelo seu `.open` (acordeao), em vez de virem todos abertos. */
  .site-nav.nav-drop.open .head-dropdown {
    display: flex;
    flex-direction: column;
    width: 100%;
  }
  .site-nav.nav-drop.open .head-dropdown-menu {
    position: static;
    min-width: 0;
    background: none;
    border: 0;
    box-shadow: none;
    padding: 0 0 0 18px;
  }
  .site-nav.nav-drop.open .head-dropdown-menu .link {
    padding: 10px 6px;
    border-bottom: 1px solid var(--line);
    border-radius: 0;
  }
  .site-nav.nav-drop .link, .site-nav.nav-drop .muted-link {
    display: block;
    padding: 11px 6px;
    font-size: 14.5px;
    border-bottom: 1px solid var(--line);
    text-align: left;
  }
  .site-nav.nav-drop .btn { display: flex; margin-top: 8px; width: 100%; }

  .site-nav.nav-icons {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 2px;
    position: static;
    background: none;
    box-shadow: none;
    padding: 0;
  }
  .site-nav.nav-icons .head-item {
    width: auto;
    height: auto;
    padding: 3px 6px 2px;
    flex-direction: column;
    justify-content: center;
    gap: 1px;
    background: none;
    border: 0;
    border-radius: 0;
    color: var(--green-dark);
  }
  .site-nav.nav-icons .head-item svg { width: 20px; height: 20px; }
  .site-nav.nav-icons .head-item:hover { color: var(--green); }
  .site-nav.nav-icons .head-item.is-active { text-underline-offset: 3px; }
  .site-nav.nav-icons .nav-label {
    display: block;
    font-size: 10px;
    line-height: 1.1;
    font-weight: 600;
    white-space: nowrap;
  }
  .site-nav.nav-icons .aff-badge { border-color: var(--paper); }
  /* Os três botões da nav anónima («Iniciar Sessão», «Novo», «Começar») com o tamanho de
     desktop empurravam a barra 15px para dentro do padding aos 390px (medido) e o menu
     inteiro ia para o hambúrguer. Um pouco mais compactos, cabem numa linha — o
     «Iniciar Sessão» é o rótulo mais largo e é ele que decide. */
  .site-nav.nav-icons .btn-sm { padding: 6px 9px; font-size: 11.5px; }
}
.link { color: var(--green-dark); text-decoration: none; font-weight: 700; font-size: 14.5px; }
.link:hover { text-decoration: underline; }
.muted-link { color: var(--muted); text-decoration: none; font-weight: 600; font-size: 14.5px; }
.muted-link:hover { color: var(--ink-700); }
.ml-auto { margin-left: auto; }

/* ---------- Mobile: o hambúrguer é o menu (≤760px) ----------
   O padrão é o do lovable.dev, em TODAS as páginas públicas: a barra leva os
   ícones e o hambúrguer leva as acções — o «Iniciar Sessão» é um botão de
   119px que espremia a barra até a encher (medido: 485/485 aos 500px de
   largura, zero folga). Antes o hambúrguer era decisão da MEDIDA (só aparecia
   quando a barra não cabia) e o resultado eram duas barras diferentes no mesmo
   telemóvel conforme a página: a entrada com «Começar» + hambúrguer, o `/home/`
   com «Iniciar Sessão» espremido entre os ícones e sem hambúrguer nenhum.
   Quem põe `mobile-hamburguer` no cabeçalho é o guião (ver base.html), e só nas
   barras de ÍCONES (`.nav-icons`): a gestão é uma lista de texto que já vive
   no hambúrguer. A entrada tem regras próprias (`landing-mobile`) que se
   SOMAM a estas — ficam no bloco logo abaixo. */
@media (max-width: 760px) {
  /* O botão do menu está sempre na barra. */
  .header-inner.mobile-hamburguer .nav-toggle { display: inline-flex; }
  /* «Iniciar Sessão» sai da barra: o hambúrguer é o sítio das acções. No painel
     volta a aparecer — a regra do `.site-nav.open` abaixo tem mais especificidade. */
  .header-inner.mobile-hamburguer .btn-entrar { display: none; }
  .header-inner.mobile-hamburguer .site-nav.open {
    display: flex;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: var(--paper-soft);
    border-bottom: 1px solid var(--line);
    box-shadow: 0 24px 40px -24px rgba(13, 20, 32, 0.35);
    padding: 10px 22px 16px;
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    z-index: 40;
  }
  /* No painel o item é uma linha «ícone + texto» à ESQUERDA, com o espaço que
     sobra à direita vazio (não centrado: a linha inteira é o alvo do toque).
     O .head-item leva também .link, cujo display:block (0,2,0) vence o
     inline-flex (0,1,0) — daí o display:flex AQUI, com a mesma especificidade
     da regra que o desfaz. */
  .header-inner.mobile-hamburguer .site-nav.open .link,
  .header-inner.mobile-hamburguer .site-nav.open .head-item {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    gap: 10px;
    padding: 11px 6px;
    font-size: 14.5px;
    border-bottom: 1px solid var(--line);
    text-align: left;
    width: auto;
    height: auto;
  }
  .header-inner.mobile-hamburguer .site-nav.open .nav-label { font-size: 14.5px; }
  /* O «Eu» não vai na barra: o painel do hambúrguer é este menu aberto, e a
     conta lá dentro é o mesmo sítio. Visto por ele em /home/ num iPhone a 125%,
     onde a barra levava «Documentos», «Painel», «Criar CV», «Eu» e o hambúrguer
     — o «Eu» duas vezes no mesmo ecrã. Sai a caixa toda (com o menu pendurado),
     não só o botão: é a mesma ideia da entrada, que faz isto ao «Documentos». */
  .header-inner.mobile-hamburguer .site-nav:not(.open) .head-conta { display: none; }
  .header-inner.mobile-hamburguer .site-nav.open .btn { display: flex; margin-top: 8px; width: 100%; }
  /* O «Iniciar Sessão» é PRIMEIRO na barra, mas no painel volta ao fim (o `order`
     de dentro do painel, não o do DOM) — ver a regra igual no `nav-collapsed`. */
  .header-inner.mobile-hamburguer .site-nav.open .btn-entrar { order: 1; }
  .header-inner.mobile-hamburguer .site-nav.open .btn-primary { order: 2; }
  /* Os dropdowns no painel: o botão é uma linha como as outras e o submenu vem
     ESTÁTICO logo a seguir (nada de absolute: no painel absolute é relativo ao
     nav e cairia sobre as linhas de baixo). Os itens ficam indentados para se
     lerem como «dentro de» do item.
     E o submenu vem JÁ ABERTO: o painel é uma lista de uma coluna, não um menu
     com gainho — esconder as opções atrás de um toque era trabalho a mais para
     o que a lista está ali para mostrar. Na barra (desktop) o submenu continua
     fechado: aí o gainho é o que evita o menu por cima da página. */
  .header-inner.mobile-hamburguer .site-nav.open .head-dropdown {
    display: flex;
    flex-direction: column;
    width: 100%;
  }
  .header-inner.mobile-hamburguer .site-nav.open .head-dropdown-menu {
    display: block;
    position: static;
    min-width: 0;
    background: none;
    border: 0;
    box-shadow: none;
    padding: 0 0 0 18px;
  }
  .header-inner.mobile-hamburguer .site-nav.open .head-dropdown-menu .link {
    padding: 10px 6px;
    border-bottom: 1px solid var(--line);
    border-radius: 0;
  }
  /* O caret aponta para cima: no painel o submenu está sempre aberto. */
  .header-inner.mobile-hamburguer .site-nav.open .head-dropdown:has(.caret) .caret { transform: rotate(180deg); }
}

/* ---------- Entrada em mobile: o resto do arranjo do lovable.dev ----------
   Só a entrada (`/`). Recebe o `landing-mobile` do guião, que se SOME ao
   `mobile-hamburguer` acima (a entrada também é uma barra de ícones, logo tem
   as duas classes). O que muda face às restantes páginas: a barra não leva
   ícones mas o botão largo, e o painel põe «Entrar» e «Começar» lado a lado no
   fundo. ⚠️ Os botões vivem DENTRO do nav (`display: contents`), por isso
   escondê-lo escondia-os também: o que se esconde são os LINKS, e o nav volta a
   `contents` para os botões ficarem na barra. */
@media (max-width: 760px) {
  .header-inner.landing-mobile .site-nav { display: contents; }
  /* O «Documentos» (button.head-item) também sai da BARRA: o padrão mobile
     é «Começar» + hambúrguer. Dentro do painel volta a aparecer (a regra
     `.site-nav.open .head-item` lá em baixo faz display:flex; aqui é só a
     barra — o nav está `display: contents` e o painel só quando `.open`). */
  .header-inner.landing-mobile .site-nav:not(.open) .head-item { display: none; }
  .header-inner.landing-mobile .nav-toggle { display: inline-flex; }
  /* No PAINEL do hambúrguer, os dois botões ficam lado a lado no fundo —
     «Entrar» à esquerda, «Começar» à direita (a mesma arrumação do
     lovable.dev). O painel é flex column; os botões passam a uma linha
     própria com `flex-direction: row` nos dois últimos filhos — feito com
     um sub-flex: os botões são irmãos directos, logo um `display: flex` no
     painel não os junta. Solução: cada botão a 50% menos o gap e o painel
     com `flex-flow: row wrap` SÓ para os botões não funciona (os links
     partiriam). O que funciona: os botões em linha via `order` + painel
     `flex-wrap: wrap` com os links a 100%. */
  .header-inner.landing-mobile .site-nav.open {
    flex-flow: row wrap;
  }
  .header-inner.landing-mobile .site-nav.open .link,
  .header-inner.landing-mobile .site-nav.open .head-item {
    width: 100%;
  }
  .header-inner.landing-mobile .site-nav.open .btn {
    margin-top: 12px;
    width: calc(50% - 6px);
  }
  /* O gap do painel (4px) soma-se às larguras: 50%-6px ×2 + gap 4 = 100%-8px,
     logo o espaçamento entre os dois é de 8px (não 12 — excedia e quebrava a
     linha, medido). */
  .header-inner.landing-mobile .site-nav.open .btn-entrar { margin-right: 8px; }
  /* A 320px o «Iniciar Sessão» não cabe em 50% (medido: quebra a linha) —
     volta a empilhar, um por linha. */
  @media (max-width: 360px) {
    .header-inner.landing-mobile .site-nav.open .btn {
      width: 100%;
      margin-right: 0;
    }
  }

  /* ---- Entrada com produto escolhido: «Novo» + «Painel» na barra ----
     Passou a haver produto escolhido (`?f=`), a barra troca o botão largo
     («Criar Carta de apresentação» são 196px — foi o que a mandou para o
     hambúrguer aos ~780px) pelos mesmos dois ícones de todas as páginas. O CTA
     não se perde: está no hero, que também segue o `?f=`. O bloco só existe
     quando há `?f=` (ver base.html) e é o `com-produto` que o liga. */
  .header-inner.landing-mobile .nav-mobile-produto {
    display: flex;
    align-items: center;
    gap: 2px;
  }
  /* Excepção à regra de cima que esconde os head-items da barra (`… .site-nav
    :not(.open) .head-item`): estes dois são a barra. */
  .header-inner.landing-mobile .site-nav:not(.open) .nav-mobile-produto .head-item { display: inline-flex; }
  /* No painel são duas linhas, e o «Novo» traz o submenu dos produtos logo a
     seguir (a regra dos head-dropdown deste painel). */
  .header-inner.landing-mobile .site-nav.open .nav-mobile-produto {
    flex-direction: column;
    align-items: stretch;
    width: 100%;
  }
  /* O CTA largo também sai (na barra e no painel): sobra o «Iniciar Sessão»,
     sozinho, a toda a largura em vez de metade. */
  .header-inner.landing-mobile.com-produto .site-nav .btn-primary { display: none; }
  .header-inner.landing-mobile.com-produto .site-nav.open .btn { width: 100%; margin-right: 0; }
}

main { min-height: 68vh; animation: page-fade 0.28s ease; }
/* O `main` é `class="container"`, e a classe ganha ao elemento (especificidade):
   `padding: 34px 0 70px` aqui nunca chegou ao ecrã e as últimas coisas de cada
   página encostavam à borda do footer. `main.container` volta a ganhar e define
   só o fundo — o topo fica como está, para não dobrar as páginas que já o
   compensam (o header, `editor-head`, `dash-head`, …). */
main.container { padding-bottom: 70px; }
@keyframes page-fade { from { opacity: 0; } to { opacity: 1; } }

/* ---------- Landing / hero ---------- */
.hero-app { padding: 34px 0 10px; }
/* As duas páginas do passo 1 (`/` e `/cv/criar/`) têm a MESMA casca: faixa do título a
   atravessar as duas colunas, o estilo à esquerda e os caminhos à direita, tudo
   alinhado à esquerda. Era `:not(.steps-only)` enquanto a criação era uma coluna só
   — o `steps-only` saiu quando as duas passaram a ser iguais. */
.hero-app .hero-main {
  text-align: left;
  /* É a coluna dos caminhos (a da direita). O tecto de 540px só se nota em ecrãs
     ≤900, onde a coluna passa a ocupar a largura toda. */
  max-width: 540px;
}
/* O rótulo do campo da IA fica centrado, como o texto do botão «Gerar com IA» logo
   abaixo. A caixa de texto NÃO se centra: centrar o que a pessoa escreve num campo é
   pior. Vale para as duas páginas que têm o campo (a entrada e a criação) — é o
   mesmo campo, com o mesmo desenho. */
.hero-app .hero-main .field label { text-align: center; }
/* Nesta coluna a dica é lida como parte do rótulo, não como outra letra: o
   `.field label small` geral deixa-a a 12.5px, peso 400 e cor muted, e aqui sobe
   ao tipo do rótulo. `color: inherit` segue o rótulo se ele mudar. O `display`
   inline já vem de `.field label small` — o `block` do `.field small` geral é
   para a dica de BAIXO do campo, não para a que está dentro do rótulo. */
.hero-app .hero-main .field label small {
  display: inline;
  margin-top: 0;
  font-size: 13.5px;
  font-weight: 600;
  color: inherit;
}
.hero-inner {
  display: grid;
  /* Primeira coluna = o estilo (passo 1), segunda = os caminhos (passo 2). As
     larguras são as que cada uma já tinha quando estavam trocadas (451 e 509):
     o carrossel continua a mostrar 2,2 cartões e os formulários os mesmos 509px. */
  grid-template-columns: 0.94fr 1.06fr;
  /* Linha (34) + os 22px que a nota tem por baixo dão os 56px de sempre. */
  gap: 34px 56px;
  /* Topos alinhados. As bases já não podem coincidir: o carrossel tem 345px de
     altura e três opções compactas não chegam lá — e distribuí-las para isso
     deixava 75px de ar entre cada uma. */
  align-items: start;
}
/* A faixa do h1 atravessa as duas colunas. */
.hero-head { grid-column: 1 / -1; }

/* ---------- Entrada: passo 2, os caminhos numa linha ---------- */
/* Duas escolhas compactas (ícone + nome) em vez de blocos de largura inteira com
   separadores «— ou —»: eram cinco blocos empilhados, e a entrada parecia uma lista
   de opções. Só a escolhida mostra o seu painel, e quem o decide é este CSS (`:has`),
   sem guião — sem JavaScript continua a haver um caminho à vista. */
.path-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: 10px;
  margin: 0 0 18px;
  /* O mesmo tecto dos painéis: senão, numa coluna larga (a do /cv/criar/), a linha
     esticava bem para lá do painel que ela governa e os bordos não batiam. */
  max-width: 540px;
}
.path-opt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  padding: 12px 9px;
  text-align: center;
  border: 1.5px solid var(--line);
  border-radius: 12px;
  background: var(--card);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.path-opt:hover { border-color: var(--line-strong); }
.path-opt:has(input:checked) { border-color: var(--green); background: var(--green-soft); }
/* O foco tem de aparecer no rótulo: o rádio está invisível (`opacity: 0`). */
.path-opt:has(input:focus-visible) { outline: 2px solid var(--green); outline-offset: 2px; }
.path-opt input { position: absolute; opacity: 0; pointer-events: none; }
.path-opt svg { width: 20px; height: 20px; color: var(--green-dark); }
.path-opt b { font-size: 12.5px; font-weight: 600; line-height: 1.25; color: var(--ink-900); }
.path-panel { display: none; max-width: 540px; }
.hero-main:has(#caminho-ficheiro:checked) .path-panel--ficheiro,
.hero-main:has(#caminho-branco:checked) .path-panel--branco { display: block; }

/* O tecto de CVs por concluir: em vez de recusar e deixar a pessoa sem saída (sem
   conta não há lista de CVs), a página volta com os que existem e o que se pode fazer
   com eles. Colunas fixas e as mesmas células em todas as linhas — e `.plain-list
   .draft-row`, porque `.plain-list li` (0,1,1) ganha a uma classe sozinha (0,1,0). */
.hero-limite { max-width: 540px; }
.plain-list .draft-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 172px;
  gap: 4px 14px;
  align-items: center;
}
.draft-quem { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.draft-quem strong { font-weight: 700; color: var(--ink-900); overflow-wrap: anywhere; }
.draft-acoes { display: flex; justify-content: flex-end; align-items: center; gap: 8px; }
.draft-acoes form { margin: 0; }
@media (max-width: 560px) {
  .plain-list .draft-row { grid-template-columns: minmax(0, 1fr); }
  .draft-acoes { justify-content: flex-start; }
}

.hero-app.pre-escolha .hero-paths .hero-main { display: none; }

/* A revelação do passo 2 é a MESMA em todo o lado: de baixo para cima. Comecei por
   fazê-la vir da direita no desktop (é a coluna da direita) e a decisão foi ter um
   só efeito nos dois sítios — o guião também faz o mesmo scroll nos dois. O
   `prefers-reduced-motion` global já desliga isto e o `both` segura o estado final. */
@keyframes surgir-de-baixo { from { opacity: 0; transform: translateY(18px); } }
.hero-app:not(.pre-escolha) .hero-paths .hero-main { animation: surgir-de-baixo 0.34s ease both; }

.hero-inner > * { min-width: 0; }

.display {
  font-family: var(--font-display);
  font-size: clamp(34px, 4.6vw, 58px);
  font-weight: 800;
  letter-spacing: -1.8px;
  line-height: 1.03;
  color: var(--ink-950);
  margin: 0;
}
.display em {
  font-family: "Fraunces", Georgia, serif;
  font-style: italic;
  font-weight: 600;
  letter-spacing: -1px;
  color: var(--gold-dark);
}
/* Realce dentro de um `.display`: o mesmo tom de verde da marca (como o «CV» do
   `.brand-hi` no rodapé), mas aqui em itálico-serifado para se manter a
   hierarquia do título — o h1 continua a ser o h1. Fica a seguir ao `.display`
   por causa da especificidade (uma classe + um elemento). */
.display .hi {
  font-family: "Fraunces", Georgia, serif;
  font-style: italic;
  font-weight: 600;
  letter-spacing: -1px;
  color: var(--green);
}
/* Título dos passos do wizard (2 a 4): mesmo tipo de letra do `.display`, mas
   mais compacto. Tem de vir DEPOIS de `.display` — mesma especificidade. */
.display.display-sm { font-size: clamp(32px, 4vw, 48px); }
.hero-sub {
  color: var(--muted);
  font-size: 16.5px;
  max-width: 460px;
  margin: 18px 0 22px;
}

/* ---------- Picker de estilo ---------- */
.style-picker {
  max-width: 640px;
  margin-bottom: 22px;
}
.picker-label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--ink-700);
  margin: 0 0 10px;
}
.picker-label::before {
  content: "";
  width: 16px;
  height: 2px;
  background: var(--green);
  border-radius: 2px;
}
.picker-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}
.tpl-nav { display: flex; gap: 8px; }
.tpl-nav-btn {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--card);
  color: var(--ink-900);
  cursor: pointer;
  font-size: 17px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.tpl-nav-btn:hover:not(:disabled) { border-color: var(--green); background: var(--green-soft); }
.tpl-nav-btn:disabled { opacity: 0.4; cursor: default; }
.tpl-carousel {
  display: flex;
  gap: 14px;
  overflow-x: auto;
  padding: 4px 4px 14px;
  scroll-snap-type: x mandatory;
  /* ATENÇÃO: tem de ser IGUAL ao `padding-left` de cima (4px). Com 2px o ponto de
     snap em repouso ficava em `scrollLeft: 2` e a guarda `scrollLeft <= 1` do
     guião das setas deixava «Anterior» activo (e morto) no início do carrossel. */
  scroll-padding-left: 4px;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
}
.tpl-carousel::-webkit-scrollbar { display: none; }
.style-card {
  position: relative;
  flex: 0 0 auto;
  width: clamp(146px, 20vw, 188px);
  cursor: pointer;
  /* O mesmo componente é `<a>` na entrada e `<label>` na criação/editor. Sem isto
     o `<a>` apanha o sublinhado e o azul do browser, e o risco atravessa o nome,
     a descrição e o preço (`.style-meta` pinta as cores, mas não apaga o risco). */
  color: inherit;
  text-decoration: none;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  padding: 0;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
  display: block;
  scroll-snap-align: start;
}
.style-card:hover { transform: translateY(-2px); }
.style-card:hover .style-preview { box-shadow: var(--shadow-lift); }
/* O foco tem de se ver no cartão (na entrada é um seletor): o rádio dentro dele está
   invisível, com `opacity: 0`, por isso o anel desenha-se aqui. */
.style-card:has(input:focus-visible) { outline: 2px solid var(--green); outline-offset: 2px; }
.style-card input { position: absolute; opacity: 0; pointer-events: none; }
/* O cartão de MODELO de carta (no editor da carta): o mesmo `.style-card`, com o
   preço ao lado do nome — a mesma leitura dos estilos da landing, e o preço
   visível antes do checkout. */
.letter-style-card { position: relative; }
.letter-style-card .style-meta b { text-decoration: none; }
.style-preview {
  display: block;
  border-radius: 4px;
  overflow: hidden;
  margin-bottom: 9px;
  box-shadow: var(--shadow);
  /* O fio marca onde acaba a folha. Sem ele, o Clássico (branco de bordo a
     bordo) parecia mais alto que os outros: a página dele confundia-se com o
     fundo e não havia aresta a fechar o cartão. */
  outline: 1px solid rgba(15, 23, 42, .10);
  outline-offset: -1px;
  position: relative;
  aspect-ratio: 210 / 297;
}
.tpl-thumb {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.style-meta {
  display: flex;
  flex-direction: column;
  line-height: 1.25;
}
.style-meta b { font-size: 13px; color: var(--ink-950); letter-spacing: -0.2px; }
/* O nome do estilo é o «título» do cartão e mantém o risco; a descrição e o preço
   não. Como o `text-decoration: none` está no `.style-card` (para o `<a>` da
   entrada não sublinhar tudo), o sublinhado tem de voltar aqui, explícito. Os 2px
   de `text-underline-offset` afastam o risco da cedilha de «Clássico»/«Técnico». */
.style-card .style-meta b { text-decoration: underline; text-underline-offset: 2px; }
.style-meta small { font-size: 11.5px; color: var(--muted); margin-top: 1px; }
/* O preço de cada modelo na faixa de estilos do editor. O mesmo cartão, sem
   preço, na entrada, já tem o preço ao fundo e à direita (`.prod-price`); aqui
   o cartão tem 146-188px e o `meta` é o nome e nada mais, por isso o preço fica
   logo abaixo do nome, à esquerda — é o que a carta faz com o
   `.letter-style-card`. A diferença para o resto dos `small` é só o peso e a
   cor: 11,5px a cinza-claro ficava a parecer parte do nome do modelo em vez de
   uma quantia. */
.style-price {
  margin-top: 3px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-700);
  letter-spacing: -0.1px;
}
/* Os cartões da LANDING alinham-se em linhas FIXAS em todos os cartões (a mesma
   grelha lê-se de cima a baixo sem escalonar):
   1-2  produto («Curriculum Vitae» / «Carta de apresentação»)
   3    nome do modelo + preço, o preço alinhado à DIREITA na mesma linha.
   O `.prod-kind` é display:block — põe o produto na sua própria linha. O nome e o
   preço vivem num `.meta-row` (flex, `space-between`) preso ao fundo, com o nome
   a encurtar com reticências para nunca empurrar o preço. */
.style-meta .prod-kind {
  display: block;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--muted);
}
.meta-row {
  margin-top: auto;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
.meta-row b {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.meta-row .prod-price { flex: 0 0 auto; margin-top: 0; }
.lp-carousel-track .style-card .style-meta b { text-decoration: none; }
/* O `.meta-row` empurra-se ao fundo do cartão com `margin-top: auto`: para isso o
   cartão é flex column e o meta enche o resto (flex: 1) — NÃO `height: 100%`, que
   resolve contra o cartão inteiro e transborda por baixo do preview. */
.lp-carousel-track .style-card { display: flex; flex-direction: column; }
.lp-carousel-track .style-card .style-preview { flex: 0 0 auto; }
.lp-carousel-track .style-meta { flex: 1; }
/* Catálogo do afiliado: a mesma grelha de cartões da entrada, mas para MOSTRAR
   (não para escolher) e responsiva. */
.cat-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 18px;
}
.cat-head h1 { font-family: var(--font-display); letter-spacing: -0.6px; margin: 0 0 6px; }
.cat-head .muted { max-width: 62ch; margin: 0; }
.cat-chip {
  flex: 0 0 auto;
  background: var(--green);
  color: #fff;
  font-weight: 800;
  font-size: 15px;
  line-height: 1;
  padding: 10px 14px;
  border-radius: 999px;
  letter-spacing: -0.2px;
  box-shadow: var(--shadow);
}
.cat-link-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-left: 4px solid var(--green);
  border-radius: var(--radius);
  background: var(--card);
}
.cat-link-info { display: flex; flex-direction: column; gap: 3px; min-width: 240px; flex: 1; }
.cat-link-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--muted);
}
.aff-link-code {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--ink-950);
  word-break: break-all;
}
.cat-acoes { display: flex; gap: 8px; flex-wrap: wrap; }
.cat-secao { margin-top: 26px; }
.cat-secao h2 {
  margin: 0 0 14px;
  font-size: 12.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--muted);
}
.cat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(196px, 1fr));
  gap: 16px;
  align-items: stretch;
}
/* O cartão do catálogo é o MESMO da entrada (`.style-card`): miniatura em cima,
   nome e preço em baixo, o preço à DIREITA na mesma linha do nome. Só muda o
   comportamento (não é clicável) e a grelha, que é responsiva. */
.cat-card {
  width: auto;
  height: 100%;
  cursor: default;
  display: flex;
  flex-direction: column;
}
.cat-card .style-preview { flex: 0 0 auto; }
.cat-card .style-meta { flex: 1; }
.cat-card .style-meta b { text-decoration: none; }
.cat-flag {
  position: absolute;
  top: 8px;
  right: 8px;
  background: var(--green);
  color: #fff;
  font-size: 11px;
  font-weight: 800;
  line-height: 1;
  padding: 4px 7px;
  border-radius: 999px;
  letter-spacing: 0.2px;
}
@media (max-width: 560px) {
  .cat-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
}
.single-cta { margin-top: 28px; max-width: 460px; }
.single-cta form { margin: 0; }
.single-cta .btn-arrow {
  font-size: 17px;
  padding: 15px 22px;
  letter-spacing: 0.2px;
}
@media (max-width: 760px) {
  .single-cta { max-width: 100%; margin-top: 22px; }
  .single-cta .btn-arrow { font-size: 15.5px; padding: 13px 18px; }
  .hero-app { padding-top: 20px; }
  .checkout-wrap, .editor-head { padding-top: 20px; }
  .hero-sub { font-size: 15px; }
}
.tags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  padding: 9px 13px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  background: #fff;
  min-height: 46px;
  cursor: text;
}
.tags:focus-within { border-color: var(--green); box-shadow: 0 0 0 3px rgba(14, 138, 94, 0.14); }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--green-soft);
  color: var(--green-dark);
  font-size: 13px;
  font-weight: 600;
  padding: 3px 6px 3px 9px;
  border-radius: 999px;
  border: 1px solid transparent;
}
.chip-x {
  border: 0;
  background: transparent;
  color: inherit;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  padding: 0 3px;
  border-radius: 999px;
  opacity: 0.65;
}
.chip-x:hover { opacity: 1; background: rgba(14, 138, 94, 0.15); }
/* ⚠️ `.chip` está DEFINIDO DUAS VEZES nesta folha: aqui, para as etiquetas do editor, e lá em
   baixo (secção `.contas`, ~5351) para as etiquetas das contas da gestão — `inline-block`,
   11.5px e `white-space: nowrap`. Como essa vem depois, ganhava ESTAS: sem `nowrap` nem
   tecto de largura, uma certificação longa saía da caixa. Medido antes do arranjo: 206px de
   sobra a 1100, 190 a 900, 260 a 760 e 288px a 390 — em todos os tamanhos.
   O `.tags` é o contentor das etiquetas do editor; o que fica escopado aqui não toca nas
   contas da gestão. Se um dia as duas se separarem, é renomear uma delas. */
.tags .chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 100%;
  white-space: normal;
  overflow-wrap: anywhere;
  padding: 3px 6px 3px 9px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--green-soft);
  color: var(--green-dark);
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 0;
}
/* O texto é quem cede: sem `min-width: 0` o item de flex não encolhe abaixo do seu conteúdo
   e volta a empurrar o ✕ para fora. */
.tags .chip-txt { min-width: 0; }
.tags .chip-x { flex: none; }
.tag-input {
  flex: 1;
  min-width: 120px;
  border: 0;
  outline: 0;
  background: transparent;
  font: inherit;
  padding: 0;
}
.tag-input:focus { border: 0; outline: 0; box-shadow: none; }
/* O painel que falhou leva um contorno a vermelho (o texto do erro vem no `messages`
   do topo do `base.html`). Era `.choice-card.card-error`, dos cartões antigos. */
.path-panel.card-error { outline: 2px solid #b3261e; }

.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  border: 1.5px dashed var(--line-strong);
  border-radius: var(--radius-sm);
  padding: 16px 10px;
  margin-bottom: 12px;
  cursor: pointer;
  color: var(--muted);
  text-align: center;
  transition: background 0.15s, border-color 0.15s;
}
.dropzone:hover, .dropzone.drag { border-color: var(--green); background: var(--green-soft); }
.dropzone strong { font-size: 13.5px; color: var(--ink-700); }
.dropzone small { font-size: 12px; color: var(--muted-light); }
.dz-plus {
  font-size: 22px;
  line-height: 1;
  color: var(--green);
  font-weight: 700;
  margin-bottom: 3px;
}

.trust-line {
  margin: 24px 0 0;
  font-size: 13.5px;
  color: var(--muted);
  display: flex;
  gap: 9px;
  flex-wrap: wrap;
  align-items: center;
}
.trust-line span { color: var(--line-strong); }
.trust-line strong { color: var(--ink-950); }

/* ---------- Landing: a coluna dos estilos ---------- */
/* O componente é o mesmo da página de criação e do editor (`.picker-top`,
   `.tpl-carousel`, `.style-card`, `.style-meta`) — vive mais acima neste ficheiro.
   Não fica nada exclusivo desta coluna: a nota «Começa pelo que gostares mais…» saiu
   a pedido (e com ela a diferença de altura entre as duas colunas do passo 1). */

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 0;
  border-radius: 11px;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 14.5px;
  padding: 11px 20px;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.15s, transform 0.06s, box-shadow 0.15s, border-color 0.15s;
  line-height: 1.3;
}
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: 0.6; cursor: wait; }
.btn .arr { font-weight: 800; }
.btn-primary { background: var(--green); color: #fff; box-shadow: 0 10px 22px -14px rgba(14, 138, 94, 0.9); }
.btn-primary:hover { background: var(--green-dark); }
/* As bordas dos botões são desenhadas com `box-shadow`/`outline` (que não
   ocupam espaço) em vez de `border`: com `border`, o botão contornado ficava
   3px mais alto que os sólidos e não alinhava lado a lado com eles. */
.btn-outline { background: var(--card); color: var(--ink-900); box-shadow: inset 0 0 0 1.5px var(--line); }
.btn-outline:hover { color: var(--green-dark); box-shadow: inset 0 0 0 1.5px var(--green); }
.btn-outline-danger { background: var(--card); color: var(--red); box-shadow: inset 0 0 0 1.5px #f1c4be; }
.btn-outline-danger:hover { background: #fdecea; color: var(--red); box-shadow: inset 0 0 0 1.5px var(--red); }
.btn-ghost { background: transparent; color: var(--green-dark); outline: 1.5px dashed #b7d8c9; outline-offset: -1.5px; }
.btn-ghost:hover { background: var(--green-soft); }
.btn-dark { background: var(--ink-950); color: #fff; }
.btn-dark:hover { background: var(--ink-700); }
.btn-whatsapp { background: var(--wa); color: #fff; }
.btn-whatsapp:hover { background: var(--wa-dark); }
/* A marca do WhatsApp dentro do botão, à medida dos outros ícones de botão
   (`.btn-import svg`, `.btn-entrar svg`). O `gap` do `.btn` dá o espaço até ao
   texto, por isso não leva margem. */
.btn-whatsapp svg { width: 16px; height: 16px; flex: 0 0 auto; }
.btn-lg { padding: 14px 26px; font-size: 15.5px; }
/* Um ícone dentro de um botão destas filas (descarregar, editar): sem medida própria, um
   SVG estica até ao tamanho do browser. O ícone do WhatsApp não passa por aqui — tem a
   regra dele, e uma regra a mais a apanhá-lo mudava-lhe o tamanho sem ninguém pedir. */
.btn-ico svg { width: 17px; height: 17px; flex: 0 0 auto; }
.btn-sm { padding: 7px 12px; font-size: 12.5px; border-radius: 8px; }
/* O «Importar de um CV antigo» é um `.btn-sm` com um ícone de ficheiro-e-seta para
   dentro. O `svg` é enorme por omissão (300×150) se não lhe dermos medida, e o
   `flex: 0 0 auto` impede-o de ser comprimido pelo texto. O `margin-left` negativo
   é o que come o `gap: 8px` do `.btn` a meio: com ele o par ícone/texto fica a 6px,
   que é o fecho dos outros botões com ícone. */
.btn-import svg { width: 15px; height: 15px; flex: 0 0 auto; margin-left: -2px; }
/* O botão do Google («Iniciar Sessão») é um `.btn` normal — esta classe só lhe dá o
   tamanho da marca, para o ícone não herdar as medidas por omissão de um `svg`. */
.btn-entrar svg { width: 15px; height: 15px; flex: 0 0 auto; }
/* O «Novo» da nav anónima é um `.btn` com o sinal de que abre um submenu (as outras
   entradas do menu da conta abrem-no também, mas levam ícone próprio). */
.btn-menu { gap: 5px; }
.btn-menu svg { width: 12px; height: 12px; flex: 0 0 auto; }
.btn-block { display: flex; width: 100%; }
.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 30px;
  padding: 0;
  border: 1.5px solid var(--line);
  border-radius: 8px;
  background: var(--card);
  color: var(--green-dark);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.btn-icon:hover { background: var(--green-soft); border-color: var(--green); color: var(--green-dark); }

/* ---------- Cards & forms ---------- */
.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 24px;
  margin-bottom: 20px;
  box-shadow: var(--shadow);
}
.card h1 { margin: 0 0 8px; font-size: 26px; font-family: var(--font-display); letter-spacing: -0.6px; }
.card h2 { margin: 0 0 14px; font-size: 17px; font-family: var(--font-display); letter-spacing: -0.3px; }
.sec-emoji { margin-right: 7px; font-size: 0.95em; }

/* O aviso da IA no editor, quando o CV nasceu de um ficheiro carregado. Não é um
   erro nem um aviso de dinheiro — é uma leitura —, e por isso leva a cor da casa
   na barra lateral em vez do âmbar ou do vermelho. */

.field { margin-bottom: 14px; }
.field label { display: block; font-weight: 600; font-size: 13.5px; margin-bottom: 6px; color: var(--ink-900); }
/* Um `<small>` DENTRO do rótulo é sempre da MESMA linha que o rótulo — é a dica
   («(opcional)», «PDF ou DOCX…») ou o contador do «Nome do documento». O
   `.field small` geral dá-lhe `display: block` (a dica de baixo do campo é que é
   uma linha própria) e com isso cada um deles caía para uma segunda linha: no
   editor o input do «Nome do documento» ficava 24px abaixo do da coluna ao lado. */
.field label small { display: inline; margin-top: 0; color: var(--muted); font-weight: 400; }
.field small { display: block; color: var(--muted); font-size: 12.5px; margin-top: 5px; }
.field input, .field textarea, .field select, .copy-row input {
  width: 100%;
  padding: 11px 13px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 15px;
  font-family: inherit;
  color: var(--ink-900);
  background: #fff;
}
.field input:focus, .field textarea:focus, .field select:focus, .copy-row input:focus {
  outline: none;
  border-color: var(--green);
  box-shadow: 0 0 0 3px rgba(14, 138, 94, 0.14);
}
.locked-hint {
  font-size: 12.5px;
  color: var(--muted);
  margin: -2px 0 14px;
}
.locked-hint a { color: var(--green-dark); font-weight: 700; text-decoration: none; border-bottom: 1px solid currentColor; }
.checkout-locked { padding: 2px 0 0; }
.checkout-locked input { display: none; }

.style-hint { margin: -8px 0 14px; color: var(--muted); font-size: 13px; }

/* O «começar por um exemplo» fica numa faixa discreta acima do `textarea`, e
   não dentro do `textarea`: o exemplo é uma escolha antes de escrever, e metê-lo
   no meio do texto empurrava o cursor e fazia a carta parecer um formulário
   preenchido.

   Os botões são a mesma gramática de `.pay-choice` (checkout): o `radio` fica
   escondido e o `label` é o que se vê. O resultado é que o que está DENTRO dos
   botões é CSS nosso — ao contrário da lista de um `select`, que é do sistema
   operativo e não se controla. E o que se vê já não é «um campo com uma seta»,
   são três opções visíveis de relance. */
.draft-picker {
  margin: 0 0 16px;
  padding: 14px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
  background: var(--green-soft, #f2f8f5);
}
/* O gerador (sem IA): o painel das quatro perguntas. Os chips são a mesma
   gramática dos radios dos exemplos — o input fica invisível e o label é o
   que se vê; marcado = fundo verde e contorno do mesmo tom (box-shadow inset,
   nunca border: soma à caixa e desalinha as alturas). */
.gerador-picker .grid-2 { margin-top: 10px; }

/* ---------- UMA pergunta, duas vias ----------
   A escolha vem primeiro, as duas opções são grandes (como os .path-opt da
   entrada) e a recomendada nasce marcada. O painel do que escolheste mostra-se
   SÓ com CSS (:has) — sem JS há sempre um painel à vista, o marcado. */
.via-choices {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 10px;
}
.via-opt {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  background: #fff;
  box-shadow: inset 0 0 0 1.5px var(--line);
  cursor: pointer;
}
.via-opt input { position: absolute; opacity: 0; pointer-events: none; }
.via-titulo { font-weight: 600; font-size: 14px; color: var(--ink-900); }
.via-desc { font-size: 12.5px; color: var(--muted); line-height: 1.4; }
.via-opt:has(input:checked) {
  box-shadow: inset 0 0 0 1.5px var(--green);
  background: var(--green-soft);
}
.via-opt:has(input:checked) .via-titulo { color: var(--green-dark); }
.via-opt:has(input:focus-visible) {
  outline: 2px solid var(--green);
  outline-offset: 1px;
}
/* O painel da via NÃO escolhida esconde-se. O gerador nasce marcado, logo o
   painel dele está à vista no arranque; ao escolher «exemplo», trocam. */
.via-panel { margin-top: 12px; }
.via-picker:has(#via-gerador:checked) .via-panel--exemplo { display: none; }
.via-picker:has(#via-exemplo:checked) .via-panel--gerador { display: none; }
@media (max-width: 620px) {
  .via-choices { grid-template-columns: 1fr; }
}
.chip-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 6px;
}
.chip-list .chip {
  display: inline-flex;
  align-items: center;
  padding: 7px 12px;
  border-radius: 999px;
  background: #fff;
  box-shadow: inset 0 0 0 1.5px var(--line);
  font-size: 13px;
  cursor: pointer;
  user-select: none;
  /* ⚠️ .chip sozinho é das TAGS do editor do CV (linha ~593): mesmo nome,
     e o antigo vencia este (mesma especificidade, vem primeiro na folha…
     na verdade vence o ÚLTIMO, mas o antigo tinha background verde que
     pintava os chips do gerador todos de «marcado»). Escopado por .chip-list
     (0,2,0) vence o antigo (0,1,0) sem lhe tocar. */
}
.chip-list .chip input { position: absolute; opacity: 0; pointer-events: none; }
/* Os botões de exemplo da carta (`.draft-exemplo`) não têm input dentro: o
   estado «escolhido» é a classe `is-active`, posta pelo JS ao clicar. */
.chip-list .chip.draft-exemplo:active { transform: translateY(1px); }
.chip-list .chip.draft-exemplo.is-active {
  background: var(--green-soft, #e7f3ee);
  box-shadow: inset 0 0 0 1.5px var(--green);
  color: var(--green-dark);
  font-weight: 600;
}
.chip-list .chip:has(input:checked) {
  background: var(--green-soft, #e7f3ee);
  box-shadow: inset 0 0 0 1.5px var(--green);
  color: var(--green-dark);
  font-weight: 600;
}
.chip-list .chip:has(input:focus-visible) {
  outline: 2px solid var(--green);
  outline-offset: 1px;
}
/* Os chips de MODELO de carta: o preço vive dentro do chip, à direita do nome.
   `small` herda a cor do chip (verde quando marcado) — é o que faz o preço
   «pertencer» ao chip e não flutuar ao lado. */
.chip-list .chip.letter-template-chip small {
  margin-left: 6px;
  font-size: 12px;
  opacity: 0.85;
}
.draft-picker > legend {
  padding: 0 6px;
  margin-left: -6px;
  font-weight: 600;
  font-size: 13.5px;
  color: var(--ink-900);
}
.draft-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.draft-choice { position: relative; }
.draft-choice input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.draft-choice label {
  display: block;
  /* `relative` como em `.pay-choice`: o `radio` está em cima, e é o `label` que
     tem de ficar a pintar por cima para receber o clique e o encaminhar para o
     `input`. Sem isto o clique ia ao `input` (invisível) e o `label` nunca
     sabia que estava a ser apontado. */
  position: relative;
  cursor: pointer;
  padding: 9px 15px;
  border: 1.5px solid var(--line);
  border-radius: 11px;
  background: #fff;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 13.5px;
  line-height: 1.3;
  color: var(--ink-900);
  transition: border-color 0.15s, background 0.15s, color 0.15s;
}
.draft-choice label:hover { border-color: var(--line-strong, #cfc7b4); }
.draft-choice input:checked + label {
  border-color: var(--green);
  background: var(--green);
  color: #fff;
}
.draft-choice input:focus-visible + label {
  outline: 2px solid var(--green);
  outline-offset: 2px;
}
.draft-picker small { display: block; margin-top: 10px; line-height: 1.45; }

.style-summary {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  padding: 12px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  max-width: 460px;
}
.style-summary-thumb {
  flex: 0 0 104px;
  width: 104px;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid var(--line);
  aspect-ratio: 210 / 297;
  display: block;
}
.style-summary-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.style-summary-info { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; }
.style-summary-name { font-size: 17px; color: var(--ink-950); letter-spacing: -0.2px; }
.style-summary-desc { font-size: 12.5px; color: var(--muted); line-height: 1.4; }
.style-summary-price { font-size: 14px; font-weight: 700; color: var(--green-dark); margin-top: 3px; }
.style-summary-change { margin-top: 8px; }
.field input.is-error,
.field textarea.is-error,
.field select.is-error {
  border-color: var(--red) !important;
}
.field input.is-error:focus,
.field textarea.is-error:focus,
.field select.is-error:focus {
  box-shadow: 0 0 0 3px rgba(179, 38, 30, 0.12);
}
/* A mensagem de erro por baixo do campo. Sem estilo, saía como um parágrafo
   cinzento qualquer logo a seguir ao `input` — e é a ÚNICA coisa que diz o que
   está errado, desde que o aviso do topo da página foi para o campo. */
.field-error {
  margin: 6px 0 0;
  color: var(--red);
  font-size: 12.5px;
  font-weight: 600;
}
.tags.is-error {
  border-color: var(--red) !important;
  box-shadow: 0 0 0 3px rgba(179, 38, 30, 0.12);
}
.exp-row.row-error,
.edu-row.row-error {
  border-color: var(--red) !important;
}
.cv-form .card.card-error {
  outline: 2px solid var(--red);
  outline-offset: 1px;
}

.grid-2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 18px; }
@media (max-width: 640px) { .grid-2 { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 900px) { .grid-account { grid-template-columns: minmax(0, 1fr); } }

/* ---------- Misc shared ---------- */
.muted { color: var(--muted); }
/* Aviso de «passa para a 2.ª página» do corpo da carta — fica sob o contador
   e só aparece perto do limite de uma folha (o JS controla o `hidden`). */
.body-page-hint { display: block; margin-top: 4px; color: #8a5a00; }
.mt { margin-top: 14px; }
.small { font-size: 13px; }
.link.strong { color: var(--green-dark); }

.flash {
  padding: 12px 16px;
  border-radius: 11px;
  margin: 14px 0 18px;
  font-size: 14px;
  font-weight: 600;
}
.flash.success { background: var(--green-soft); color: var(--green-dark); border: 1px solid #bfe6d5; }
.flash.error { background: #fdecea; color: var(--red); border: 1px solid #f5c6c0; }
/* O aviso informativo era `paper-soft` sobre `paper`: dois tons de creme a 4 pontos
   de distância, e o texto só se via se a pessoa estivesse à espera dele. Passa a
   ser um cartão escuro — o mesmo `ink` do cabeçalho — com barra azul à esquerda.
   É o aviso que explica porque é que fomos atirados para outra página; tem de
   ser a primeira coisa que o olho encontra. */
.flash.info {
  background: var(--ink-950);
  color: #f7f5ef;
  border: 1px solid var(--ink-950);
  border-left: 4px solid #2563eb;
  box-shadow: 0 10px 26px -12px rgba(13, 20, 32, .45);
}
.flash.info .flash-x { color: #f7f5ef; }
.flash.info .flash-x:hover { background: rgba(255, 255, 255, .14); }
/* O aviso é um toast: uma linha, um ✕, e sai sozinho (o guião do `base.html`). O `transform`
   existe para a saída não ser um corte seco. */
/* Os avisos são uma CAMADA fixa por cima do conteúdo, não uma linha no topo do
   `<main>`. Antes, quando aparecia o «Atingiste o limite…», o aviso empurrava
   tudo o que estava abaixo — e ao desaparecer (6 s, ou o ✕) puxava tudo para
   cima outra vez. Duas quebras de layout por um aviso de uma linha, no meio de
   alguém a escrever o CV. Fixo, não ocupa lugar nenhum: aparece por cima e sai
   sem mexer no que está por baixo. */
.flashes {
  position: fixed;
  top: 74px;                      /* 62px do cabeçalho + 12px de ar */
  left: 50%;
  transform: translateX(-50%);
  z-index: 35;                    /* acima do conteúdo, abaixo dos modais (90+) */
  width: min(520px, calc(100vw - 24px));
  display: grid;
  gap: 8px;
  margin: 0;
  pointer-events: none;           /* a camada não apanha cliques; os avisos sim */
}
.flashes .flash {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 0;
  pointer-events: auto;
  animation: aviso-entrar .22s ease-out;
}
@keyframes aviso-entrar {
  from { opacity: 0; transform: translateY(-10px); }
  to { opacity: 1; transform: none; }
}
@media (max-width: 760px) {
  .flashes { top: 66px; }         /* cabeçalho de 58px no telemóvel */
}
.flashes .flash > span { flex: 1 1 auto; min-width: 0; }
.flash-x {
  flex: none; border: 0; background: transparent; cursor: pointer; color: inherit;
  font: inherit; font-size: 12px; line-height: 1; padding: 3px 5px; border-radius: 6px;
  opacity: .55;
}
.flash-x:hover { opacity: 1; background: rgba(13, 20, 32, .07); }
.flash.is-saindo { opacity: 0; transform: translateY(-4px); transition: opacity .25s ease, transform .25s ease; }

.notice {
  border-radius: 11px;
  padding: 12px 14px;
  font-size: 14px;
  background: var(--gold-soft);
  border: 1px solid #ecdcae;
  margin-top: 14px;
}
/* Só tinha margem em cima: o aviso encostava ao que vinha a seguir — o «Comissões sem destino»
   do Afiliado tocava no cartão «Levantar» (medido: folga 0). Com algo depois, leva a folga dos
   cartões (20px); em último lugar fica com o padding do cartão que o contém. */
.notice:not(:last-child) { margin-bottom: 20px; }
.notice a { color: var(--green-dark); font-weight: 700; display: block; margin-top: 4px; }
.notice-error { background: #fdecea; border-color: #f5c6c0; color: var(--red); }


.badge { display: inline-block; padding: 4px 11px; border-radius: 999px; font-size: 12.5px; font-weight: 700; }
.badge-pending { background: var(--gold-soft); color: var(--gold-dark); }
.badge-ok { background: var(--green-soft); color: var(--green-dark); }
.badge-approved { background: var(--green-soft); color: var(--green-dark); }
.badge-grey { background: #eef0f3; color: var(--ink-700); }
.badge-green { background: var(--green-soft); color: var(--green-dark); }
.badge-gold { background: var(--gold-soft); color: var(--gold-dark); }
.badge-red { background: #fdeceb; color: var(--red); }

.kv { list-style: none; margin: 0; padding: 0; }
.kv li { display: flex; justify-content: space-between; gap: 12px; padding: 9px 0; border-bottom: 1px dashed var(--line); }
.kv li:last-child { border-bottom: 0; }
.kv span { color: var(--muted); }

/* ---------- Conta ---------- */
.account-head { display: flex; align-items: center; gap: 14px; margin-bottom: 14px; }
.account-head-main { min-width: 0; flex: 1; }
/* A galeria enche a página (sem um limite interior): os cartões chegam às margens do
   `.container` e a tiragem A4 lê-se como um documento, como no Jobseeker. */
.cvs-wrap { }
.card-head-actions { display: flex; align-items: center; gap: 10px; margin-left: auto; }
.card-head-title { display: flex; align-items: center; gap: 12px; min-width: 0; }
.cv-filter-box { position: relative; }
/* O botão do filtro DIZ o filtro escolhido, em vez de só ficar verde. Verde
   sozinho era ambíguo: a mesma cor pintava o «filtrado» e o «hover», e o título
   da página é a única pista que sobrava — quem chega por um link com `?estado=`
   via de uma vista que não mostra nada. Sem filtro o botão é o quadradinho do
   funil (38px, como estava); com filtro cresce para o nome, que é o que se quer
   ler à distância. */
.cv-filter-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-width: 38px;
  height: 38px;
  padding: 0 8px;
  border-radius: 10px;
  color: var(--ink-800);
  background: var(--card);
  border: 1.5px solid var(--line);
  cursor: pointer;
}
.cv-filter-btn svg { width: 17px; height: 17px; flex: 0 0 auto; color: var(--muted); transition: transform 0.15s ease; }
.cv-filter-label { font-size: 13px; font-weight: 700; line-height: 1; white-space: nowrap; }
.cv-filter-btn:hover { border-color: var(--green); }
.cv-filter-btn.is-filtered { padding: 0 12px; border-color: var(--green); background: var(--green-soft); }
.cv-filter-btn.is-filtered svg { color: var(--green-dark); }
.cv-filter-btn.is-filtered .cv-filter-label { color: var(--green-dark); }
.cv-filter-btn[aria-expanded="true"] svg { transform: rotate(180deg); }
.cv-filter-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 40;
  min-width: 210px;
  padding: 6px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 12px 30px rgba(10, 18, 28, 0.16);
}
.cv-filter {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 10px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink-800);
  text-decoration: none;
}
.cv-filter:hover { background: var(--surface); }
.cv-filter.is-active { background: var(--ink-950); color: #fff; }
.cv-filter-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--green);
  flex: none;
}
.cv-filter.is-active .cv-filter-dot { background: #fff; }
.cv-count {
  margin-left: auto;
  font-size: 11px;
  font-weight: 800;
  background: var(--green-soft);
  color: var(--green-dark);
  border-radius: 999px;
  padding: 1px 7px;
}
.cv-filter.is-active .cv-count { background: rgba(255,255,255,0.18); color: #fff; }
.pager { display: flex; align-items: center; justify-content: center; gap: 10px; padding: 14px 0 4px; }
.pager-btn {
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 700;
  color: var(--green-dark);
  text-decoration: none;
  border: 1.5px solid var(--line);
  border-radius: 9px;
  background: var(--card);
}
.pager-btn:hover { border-color: var(--green); }
.pager-btn.is-disabled { opacity: 0.4; pointer-events: none; }
.pager-info { font-size: 13px; color: var(--muted); font-weight: 600; }
.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
  flex-wrap: wrap;
}
.card-head h2 { margin: 0; }
.card-head .btn { flex: 0 0 auto; }
.account-name { font-size: 18px; font-weight: 800; font-family: var(--font-display); margin: 0 0 2px; }
.avatar { width: 56px; height: 56px; border-radius: 50%; object-fit: cover; flex: none; }
.avatar-fallback {
  display: inline-flex; align-items: center; justify-content: center;
  width: 56px; height: 56px; border-radius: 50%; flex: none;
  background: var(--green-dark); color: #fff; font-size: 24px; font-weight: 800;
}
.plain-list { list-style: none; margin: 0; padding: 0; }
.plain-list li { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; padding: 9px 0; border-bottom: 1px dashed var(--line); }
.plain-list li:last-child { border-bottom: 0; }

/* ---------- Editor ---------- */
.editor-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px 20px;
  flex-wrap: wrap;
  /* O cabeçalho (nome do documento + acções) é o TOPO do editor (a pedido,
     Out/2026): antes vinha depois da faixa de estilos. Este ar separa-o da faixa
     e, por ela, do primeiro cartão de conteúdo. */
  margin-bottom: 26px;
}
/* Os botões do canto não podem esmagar o título: sem isto, o «Importar de um CV antigo»
   baixava o campo de 38px para 32px. O `min-width` é o que decide a quebra — medido
   é que a 768px o campo ficava com 340px (19 caracteres à vista) e a partir dos
   ~810px passava a ter a largura toda, 720px. A quebra do `flex` acontece pelo
   `min-width`, por isso não há breakpoint: se não couber o botão AO LADO do
   mínimo, o botão desce. */
.editor-head-titulo { min-width: min(100%, 430px); flex: 1 1 320px; }
.editor-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: flex-start;
  /* O `margin-left: auto` é o que segura o «Importar de um CV antigo» à direita também
     depois de descer de linha. Sem ele o `space-between` do `.editor-head` só
     distribui o que está na MESMA linha: quando o `flex-wrap` atira as ações
     para baixo, ficavam órfãs à esquerda (medido: a partir de ~810px, e em
     qualquer largura de telemóvel). Na mesma linha o `auto` não faz nada — quem
     empurra para a direita é o `flex: 1` do título, que enche a folga. */
  margin-left: auto;
}
.cv-form .card { margin-bottom: 18px; }

/* Faixa de estilos do editor. NÃO volta a ter CSS próprio: a fila é o
   `.tpl-carousel` e os cartões os `.style-card` da entrada — os mesmos que já
   se conhecem, e que a grelha de quatro colunas desviava (246px de largura,
   miniatura de 232×329, e a partir de cinco ou seis estilos já não caíam). O que
   fica aqui é só a diferença entre o clique da landing e o de aqui. */
.style-strip { margin: 0 0 18px; }
/* Na entrada o cartão activo é um `<label>` com um `radio` dentro, de onde vem o
   `:has(input:checked)`. Aqui o clique é um `<button>` — não há input para
   esconder — por isso o estado vem por `.is-active`, posto pelo servidor e
   atualizado pelo `fetch` da troca. É a única regra do estado escolhido.
   O anel era `--green-soft` (#e6f4ee): uma linha lavada, que não se lê de longe —
   com dez cartões na fila, o escolhido tem de saltar à vista. */
.style-card.is-active .style-preview,
.style-card:has(input:checked) .style-preview {
  box-shadow: 0 0 0 3px var(--green), var(--shadow);
}
button.style-card {
  /* O `<button>` não herda a tipografia nem alinha o texto à esquerda. */
  font: inherit;
  text-align: left;
  color: inherit;
  cursor: pointer;
}
button.style-card:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }

/* O selo do modelo escolhido: a palavra, além do anel. Vive em todos os cartões e
   só aparece no activo — o JS que troca de modelo não tem de reescrever texto. */
.style-selo {
  position: absolute;
  top: 8px;
  right: 8px;
  display: none;
  align-items: center;
  gap: 4px;
  padding: 3px 9px 3px 7px;
  border-radius: 999px;
  background: var(--green);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  box-shadow: 0 2px 8px rgba(12, 30, 22, 0.22);
  pointer-events: none;
}
.style-card.is-active .style-selo,
.style-card:has(input:checked) .style-selo { display: inline-flex; }

/* O nome do documento é o TÍTULO do editor: a `h1` da página está no ecrã só
   para leitores, e o que se vê em grande é o campo que dá o nome a este CV na
   conta. Antes era o contrário — «Editar CV» a 48px e o nome do documento atirado
   para dentro de «Dados pessoais», ao lado do nome completo, que é outra coisa. */
/* Onde o editor abre (`_ancora_do_editor`), com a folga do cabeçalho do site, que é
   `sticky` com 62px: sem o `scroll-margin-top` o alvo aterrava POR BAIXO dele. Os
   ~38px a mais deixam ver a ponta do bloco anterior — é o sinal de que há conteúdo
   por cima. */
#doc-nome, #photo-card, #dados { scroll-margin-top: 100px; }
.doc-name-top { margin-bottom: 6px; }
.doc-name-count {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--muted);
  transition: color 0.15s ease;
}
.doc-name-count[data-full="1"] { color: var(--red); }.doc-name-input {
  display: block;
  width: 100%;
  border: 0;
  border-bottom: 2px solid var(--line);
  border-radius: 0;
  background: transparent;
  padding: 0 0 8px;
  font-family: var(--font-display);
  font-size: clamp(26px, 4.2vw, 38px);
  font-weight: 800;
  letter-spacing: -0.8px;
  /* 1.15 cortava o texto dentro da caixa do input: um input não cresce pela linha, e a
     fonte a 38px é mais alta do que 1.15 linhas. */
  line-height: 1.4;
  color: var(--ink-950);
  transition: border-color 0.15s ease;
}
.doc-name-input::placeholder { color: var(--ink-300); }
.doc-name-input:hover { border-bottom-color: var(--line-strong); }
/* O nome do documento é o único campo marcado que não está dentro de uma
   `.field`, por isso fica de fora do `.field input.is-error` de cima. A marca é
   a mesma (borda vermelha) para que o campo errado se pareça com os outros. */
.doc-name-input.is-error { border-bottom-color: var(--red) !important; }
/* O seletor de modelo da carta: mesma linha do nome do documento, mas discreto
   (não é um título). Herda a borda inferior para ficar na mesma grelha. */
.letter-template-select {
  max-width: 280px;
  padding: 6px 8px;
  border: 1.5px solid var(--line);
  border-radius: 8px;
  background: #fff;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink-900);
}
.doc-name-input:focus {
  outline: none;
  border-bottom-color: var(--green);
}

.exp-row, .edu-row, .proj-row {
  border: 1px solid var(--line);
  border-radius: 11px;
  padding: 14px;
  margin-bottom: 12px;
  background: var(--paper-soft);
  position: relative;
}
.exp-row .grid-3 { display: grid; grid-template-columns: 1.4fr 1fr 0.8fr 0.8fr; gap: 10px; }
.edu-row .grid-3 { display: grid; grid-template-columns: 1.4fr 1fr 0.8fr 0.7fr; gap: 10px; }
.proj-row .grid-3 { display: grid; grid-template-columns: 1.6fr 1.4fr 0.7fr; gap: 10px; }
@media (max-width: 680px) {
  .exp-row .grid-3, .edu-row .grid-3, .proj-row .grid-3 { grid-template-columns: 1fr 1fr; }
}
.row-remove {
  position: absolute;
  top: 10px;
  right: 10px;
  border: 0;
  background: transparent;
  color: var(--red);
  font-size: 12.5px;
  cursor: pointer;
  font-weight: 700;
  /* Alvo de toque: a caixa passava de 16px de altura. O `padding` cresce a caixa
     e a margem negativa da mesma medida a recoloca onde estava — o «Remover»
     fica igual à vista e passa a ter 36px de altura. */
  padding: 10px 6px;
  margin: -10px -6px;
}
.row-remove:hover { text-decoration: underline; }
.row-title { font-weight: 800; font-size: 12px; color: var(--muted); margin-bottom: 10px; text-transform: uppercase; letter-spacing: 0.6px; }

/* Línguas com nível: uma linha compacta por língua (nome + nível + remover).
   O nome e o nível são os mesmos campos caixa dos outros (.field input/select):
   se ficassem nus (border 0, fundo transparente), eram as únicas controlos do
   editor a não ter «pegada». */
/* A grelha do Quadro Europeu abre por baixo da linha, e ocupa-a toda: é a
   mesma língua, não uma coluna ao lado. */
.lang-cefr { grid-column: 1 / -1; }
.lang-cefr > summary { cursor: pointer; font-size: 12.5px; color: #5b6470; padding: 2px 0; }
.lang-cefr .cefr-grid { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 0 10px; margin-top: 6px; }
.lang-cefr .cefr-campo { display: block; }
.lang-cefr .cefr-campo span { display: block; font-size: 11.5px; color: #5b6470; margin-bottom: 2px; }
@media (max-width: 640px) { .lang-cefr .cefr-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.lang-row {
  display: grid;
  grid-template-columns: 1fr 220px 34px;
  gap: 10px;
  align-items: center;
  border: 1px solid var(--line);
  border-radius: 11px;
  padding: 10px 12px;
  margin-bottom: 10px;
  background: var(--paper-soft);
}
.lang-row .lang-name,
.lang-row .lang-level,
/* Os cinco selects da grelha são campos do editor como os outros: sem esta
   linha ficavam com o desenho do browser no meio de um formulário desenhado. */
.lang-cefr select {
  width: 100%;
  min-width: 0;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  background: #fff;
  padding: 9px 12px;
  font-size: 15px;
  font-family: inherit;
  color: var(--ink-900);
}
.lang-row .lang-name:focus,
.lang-row .lang-level:focus,
.lang-cefr select:focus {
  outline: none;
  border-color: var(--green);
  box-shadow: 0 0 0 3px rgba(14, 138, 94, 0.14);
}
.lang-x { font-size: 16px; }
@media (max-width: 680px) {
  /* `1fr 150px 34px` esmagava o nome da língua — medido: 26px de largura a 320px
     e 66px a 390px, com o nível a ocupar 150px. Em ecrãs estreitos o nível
     desce para a sua linha e o nome fica com a largura toda. */
  .lang-row { grid-template-columns: minmax(0, 1fr) 34px; }
  .lang-row .lang-name { grid-column: 1; grid-row: 1; }
  .lang-row .lang-level { grid-column: 1; grid-row: 2; }
  .lang-row .lang-x { grid-column: 2; grid-row: 1 / span 2; align-self: center; }
}

.form-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 18px; }
/* A fila do fundo encostada à direita: a acção principal fica do mesmo lado do botão do
   cabeçalho (`.admin-head`, que é `space-between`). Sem isto, a mesma acção aparecia à esquerda
   num cartão e à direita no cabeçalho. */
.form-actions.dir { justify-content: flex-end; }
.form-section-title { margin: 24px 0 4px; font-size: 15px; font-weight: 800; color: var(--ink-900); }
.hint-error { color: var(--red); font-weight: 700; }
input.is-invalid, select.is-invalid { border-color: var(--red); box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.12); }
/* O botão que fecha o documento. No telemóvel fica à mão — o polegar não tem de
   percorrer o formulário inteiro para saber o preço e seguir. No computador é
   uma linha normal no fim: uma barra a flutuar sobre um formulário de duas
   colunas não se lê como «o botão deste documento», lê-se como sobreposição. */
.sticky-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  flex-wrap: wrap;
  /* `stretch` (o default) esticava o estado de «a guardar…» à altura do botão
     (medido: 48.1px de caixa para 19.4px de texto) e o texto ficava colado ao
     topo em vez de centrado com o botão. */
  align-items: center;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}
@media (max-width: 760px) {
  .sticky-actions {
    position: sticky;
    bottom: 10px;
    margin-top: 14px;
    padding: 10px;
    border-top: 0;
    border-radius: 12px;
    background: rgba(247, 245, 239, 0.94);
    backdrop-filter: blur(6px);
    box-shadow: 0 -8px 22px -18px rgba(12, 30, 22, 0.45);
  }
}

/* ---------- Checkout / order ---------- */
.checkout-wrap, .order-wrap { max-width: 620px; margin: 0 auto; }
/* Os passos 3 e 4 começam à mesma altura do hero dos passos 1 e 2. */
.checkout-wrap, .editor-head { padding-top: 34px; }
@media (min-width: 900px) {
  .checkout-wrap.checkout-wide { max-width: 1120px; }
}
/* O título da página é à esquerda, como o dos painéis: centrado, a Definições e o Afiliado
   ficavam com outro desenho («ainda está com o título centrado ... Definições tb»). */
.order-head { margin: 26px 0 22px; }
.order-head h1 { font-family: var(--font-display); letter-spacing: -0.6px; margin-bottom: 4px; }
.order-card { text-align: center; }
.order-code {
  background: var(--ink-950);
  color: #fff;
  border-radius: 11px;
  padding: 14px;
  margin-bottom: 12px;
}
.order-code small { display: block; color: #9fb3c9; font-size: 11px; text-transform: uppercase; letter-spacing: 1.5px; margin-bottom: 4px; font-family: var(--font-mono); }
.order-code strong { font-family: var(--font-mono); font-size: 21px; letter-spacing: 1px; }
.pay-steps { margin: 0 0 16px; padding-left: 20px; color: var(--ink-900); }
.pay-steps li { margin-bottom: 8px; font-size: 14.5px; }
.mcx-box { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 12px; }
.mcx-box > div {
  border: 1.5px dashed #b7d8c9;
  border-radius: 11px;
  padding: 12px;
  text-align: center;
  background: var(--paper-soft);
}
.mcx-box span { display: block; color: var(--muted); font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.5px; font-family: var(--font-mono); }
.mcx-box strong { font-size: 18px; font-family: var(--font-mono); }
@media (max-width: 520px) { .mcx-box { grid-template-columns: 1fr; } }
.pay-how-num { font-family: var(--font-mono); font-weight: 600; color: var(--ink-900); white-space: nowrap; }
/* O ecrã de pagamento pela ordem de quem paga (a pedido, Out/2026): em que passo
   está (a barra), quanto e para onde (o cartão verde e os dois dados), e o que fazer
   a seguir (os botões). */
.passos { display: flex; gap: 8px; margin: 0 0 24px; padding: 0; list-style: none; }
.passos li { flex: 1 1 0; min-width: 0; }
.passos .barra { display: block; height: 3px; border-radius: 2px; background: var(--line); }
.passos .rotulo { display: block; margin-top: 9px; font-size: 13px; line-height: 1.3; color: var(--muted-light); }
.passos .feito .barra, .passos .agora .barra { background: var(--green); }
.passos .feito .rotulo { color: var(--green-dark); font-weight: 600; }
.passos .agora .rotulo { color: var(--ink-900); font-weight: 700; }
.pedido-h { margin: 0 0 6px; }
.pedido-sub { margin: 0 0 20px; font-size: 14.5px; line-height: 1.5; }
/* Quanto se paga, em cartão próprio: é o número que a pessoa vai escrever no
   Multicaixa e merece o maior tipo do ecrã. */
.valor-card { background: var(--green); color: #fff; border-radius: var(--radius); padding: 16px 20px 18px; margin-bottom: 14px; box-shadow: var(--shadow); }
.valor-label { display: block; font-size: 13.5px; opacity: 0.88; margin-bottom: 6px; }
.valor-num { font-family: var(--font-display); font-size: 42px; font-weight: 800; letter-spacing: -1.5px; line-height: 1; }
.valor-num small { font-size: 17px; font-weight: 700; letter-spacing: 0; margin-left: 5px; }
/* Os dois dados que se copiam, um por linha: rótulo pequeno, valor grande e o
   botão à direita — o alvo que o dedo encontra sem procurar. */
.dados-pagamento { padding: 0; margin-bottom: 14px; overflow: hidden; }
.dado { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 13px 16px; }
.dado + .dado { border-top: 1px solid var(--line); }
.dado-texto { min-width: 0; }
.dado-label { display: block; font-size: 13px; color: var(--muted); margin-bottom: 3px; }
.dado-valor { display: block; font-family: var(--font-mono); font-size: 18px; font-weight: 600; color: var(--ink-900); white-space: nowrap; }
.dado-copiar { flex: none; }
/* A única coisa que se pede à pessoa para fazer na transferência — e a que mais se
   esquece. Âmbar: chama a atenção sem ser erro. */
.aviso-amber { background: var(--gold-soft); border: 1px solid #ecd9a8; color: var(--gold-dark); border-radius: var(--radius-sm); padding: 12px 14px; font-size: 14px; line-height: 1.5; margin: 0 0 24px; }
.pagar-h { font-family: var(--font-display); font-size: 19px; margin: 0 0 12px; }
/* Empilhados: em telemóvel os dois botões em linha ficavam com metade da largura
   cada e o rótulo do comprovativo partia-se em duas linhas. */
.order-cta-col { display: flex; flex-direction: column; align-items: stretch; gap: 10px; }
.order-cta-col .btn { width: 100%; justify-content: center; }
/* O download por pagar: contorno tracejado, que se lê como «ainda não» sem balão
   nenhum — e a frase por baixo diz porquê. */
.btn-pontilhado { border: 1.5px dashed var(--line-strong); background: transparent; color: var(--muted); }
.pagar-nota { text-align: center; margin: 2px 0 0; }
.pay-note { margin: 0 0 10px; font-size: 13.5px; line-height: 1.55; color: var(--muted); }
/* A porta do apoio, por baixo dos botões: pequena, para não competir com o botão
   do comprovativo, e com o mesmo rótulo do rodapé (o que o link faz, não o que
   ele podia fazer). O ícone precisa do tamanho aqui — sem regra, um SVG sem
   largura própria estica até ao tamanho do browser. */
.order-support { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin: 14px 0 0; }
.order-support-link {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--ink-700); font-weight: 600; text-decoration: none;
}
.order-support-link:hover { text-decoration: underline; }
.order-support-link svg { width: 15px; height: 15px; flex: none; }
/* Os dois botões em linha: o comprovativo é o que falta fazer agora, o download
   é o que vem depois e ainda não está disponível. Em ecrã estreito empilham. */
.order-cta { display: flex; flex-wrap: wrap; gap: 10px; }
.order-cta .btn { flex: 1 1 190px; }
/* Pedido compacto: foco no CTA, detalhes recolhidos */
.order-compact { max-width: 520px; }
/* Aqui a cabeça não tem título nenhum — o que ela centra é o «Painel de documentos». Fica. */
.order-compact .order-head { text-align: center; margin-bottom: 14px; }
.order-compact .order-head h1 { font-size: 24px; margin-bottom: 2px; }
.order-compact .order-head .muted { font-size: 14px; }
.order-compact .card { padding: 20px; }
/* Apertar o ecrã do pedido (a pedido, Out/2026): «até 125% os elementos devem estar
   visíveis». Medido a 500px de largura, com o tipo e as folgas de antes: os botões
   acabavam aos 906px e o «Descarregar PDF» — que é o que a pessoa veio buscar — era
   a última coisa da página. Cada bloco dá alguns pixels (o cartão dos dados perdia
   40 só no padding que vinha do `.card`), e a soma são ~170px.

   Tudo preso a `.order-compact`, que é o ecrã do pedido: o assistente e o checkout
   partilham `.passos` e `.card`, e não encolhem com ele. */
.order-compact .order-head { margin-bottom: 0; }
/* Três classes de propósito: a regra do `.back-link` do pedido vive mais abaixo no
   ficheiro (`.order-wrap .back-link`, com o mesmo peso) e ganhava a esta. */
.order-compact.order-wrap .back-link { padding: 6px 14px; margin-bottom: 10px; }
.order-compact .passos { margin-bottom: 14px; }
.order-compact .passos .rotulo { margin-top: 6px; }
.order-compact .pedido-h { font-size: 23px; }
.order-compact .pedido-sub { margin-bottom: 12px; }
/* O preço é contexto, não é acção: nesta página o único verde é o botão.
   Uma linha só, rótulo à esquerda e valor à direita, sem sombra nem bloco. */
.order-compact .valor-card {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: 4px 12px;
  padding: 11px 15px; margin-bottom: 10px;
  background: #fff; color: var(--ink-900);
  border: 1px solid var(--line); box-shadow: none;
}
.order-compact .valor-label { margin: 0; opacity: 1; color: var(--muted); font-size: 13px; }
.order-compact .valor-num { font-size: 24px; letter-spacing: -0.6px; }
.order-compact .valor-num small { font-size: 15px; }
/* O `.card` traz 20px de padding por dentro; aqui os dados têm o seu, linha a linha. */
.order-compact .dados-pagamento { padding: 0; margin-bottom: 10px; }
.order-compact .dado { padding: 10px 14px; }
.order-compact .dado-label { margin-bottom: 2px; }
.order-compact .aviso-amber { padding: 9px 12px; margin-bottom: 12px; }
.order-compact .pagar-h { font-size: 17px; margin-bottom: 8px; }
.order-compact .order-cta-col { gap: 8px; }
.order-compact .pagar-nota { font-size: 12.5px; }
.order-compact .order-support { margin-top: 10px; }
/* A grelha do pagamento ao contrário dos 3 lados: o número de telefone é o
   valor mais longo da página e a 18px não cabe numa coluna de 150px, que é o
   que sobra de 520px menos o padding do cartão. Vai com o valor na primeira
   linha e o pedido sozinho em baixo, largo. A 18px monoespaçado, «+244 900
   000 000» mede ~162px e transbordava. */
.order-compact .mcx-box { grid-template-columns: 1fr 1fr; }
.order-compact .mcx-box > div:last-child { grid-column: 1 / -1; }
.order-compact .mcx-box strong { font-size: 17px; }
/* Sair do pedido: uma linha quieta, abaixo do cartão de pagamento e longe do
   CTA. Fica separada por uma regra para não parecer parte do pagamento. */
.order-quit {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  text-align: center;
}
.order-quit .btn { font-size: 14px; padding: 8px 14px; }
.order-quit .muted { font-size: 13px; margin: 8px 0 0; }
.order-meta {
  margin-top: 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fff;
  overflow: hidden;
}
.order-meta > summary {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-900);
  list-style: none;
}
.order-meta > summary::-webkit-details-marker { display: none; }
.order-meta > summary:after {
  content: "▾";
  margin-left: auto;
  color: var(--muted);
  transition: transform 0.15s ease;
}
.order-meta[open] > summary:after { transform: rotate(180deg); }
.order-meta .kv { margin: 0; padding: 2px 16px 14px; }
/* Detalhes sempre abertos (Out/2026): o ecrã do pedido passou a ter um botão só e
   estes dados lêem-se sem clique. A cabeça é um h2, não uma summary. */
.order-meta-h {
  display: flex; align-items: center; gap: 10px;
  margin: 0; padding: 12px 16px 4px;
  font-size: 14px; font-weight: 600; color: var(--ink-900);
}
.order-meta-h .badge { margin-left: auto; }
.order-meta .kv li { padding: 7px 0; }
.order-meta .kv li + li { border-top: 1px solid var(--line); }
/* O botão hero do pedido: ícone e texto à esquerda, seta à direita. */
.order-cta-col .btn-hero-pdf { position: relative; display: flex; align-items: center; justify-content: center; gap: 10px; padding: 12px 44px; min-height: 46px; font-size: 15px; }
.btn-hero-pdf .hero-lado { display: inline-flex; align-items: center; gap: 8px; }
/* A seta fica na borda direita como sinal de saída; o rótulo é que ocupa o meio. */
.btn-hero-pdf .arr { position: absolute; right: 16px; top: 50%; transform: translateY(-50%); font-size: 18px; line-height: 1; }
/* Uma linha, discreta, a dizer o que o botão faz — a dúvida de quem está a pagar. */
.hero-nota {
  display: flex; align-items: flex-start; gap: 7px;
  margin: 2px 0 4px; padding: 0 6px;
  font-size: 12.5px; line-height: 1.45; color: var(--muted); text-align: left;
}
.hero-nota svg { width: 15px; height: 15px; flex: 0 0 auto; margin-top: 1px; }
/* Valor do pedido: uma linha, e a nota por baixo diz como se paga. */
.order-compact .valor-nota {
  flex-basis: 100%;
  margin-top: 6px;
  font-size: 12.5px; line-height: 1.4; color: var(--muted);
  /* Encostada à direita, debaixo do número: é o segundo preço da mesma coisa,
     não uma frase a acompanhar o rótulo. */
  text-align: right;
}
/* «O teu pedido está registado»: o sossego de quem acabou de carregar no botão. */
/* Dois caminhos de pagamento, um ao lado do outro e do mesmo tamanho.
   Empilhados, o segundo lia-se como plano B; e no telemóvel a altura fixa
   impede que o texto de um deles faça o outro crescer desalinhado. */
.pay-escolha {
  margin: 18px 0 8px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: #64748b;
}
.pedido-ctas {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.pedido-ctas form { display: flex; margin: 0; }
.pedido-ctas .btn,
.pedido-ctas button {
  width: 100%;
  min-height: 52px;
  padding: 10px 12px;
  font-size: 15px;
  font-weight: 700;
  justify-content: center;
  gap: 8px;
  border-radius: 12px;
}
.pedido-ctas button { cursor: pointer; border: 0; }
.pedido-nota-pagamento {
  margin: 10px 0 0;
  font-size: 13px;
  line-height: 1.45;
  color: #64748b;
}

/* Cartão, para quem está fora de Angola: um bloco discreto por baixo do
   botão do WhatsApp — é alternativa, não concorrência. */
.cartao-box {
  margin-top: 14px;
  padding: 14px 16px;
  border: 1px solid rgba(15, 23, 42, .12);
  border-radius: 12px;
  background: #fff;
}
.cartao-titulo {
  margin: 0 0 2px;
  font-size: 14px;
  font-weight: 700;
  color: var(--ink-950, #0f172a);
}
.cartao-sub {
  margin: 0 0 10px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--muted, #64748b);
}
.cartao-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  min-height: 44px;
  padding: 10px 16px;
  border-radius: 10px;
  border: 1px solid rgba(15, 23, 42, .18);
  background: #f8fafc;
  color: #0f172a;
  font: inherit;
  font-weight: 650;
  cursor: pointer;
}
.cartao-btn:hover { background: #eef2f7; }

.pedido-confia {
  display: flex; align-items: flex-start; gap: 10px;
  margin: 4px 0 2px; padding: 10px 12px;
  border-radius: 11px;
  background: var(--green-soft, #eaf6ef);
}
.pedido-confia svg { width: 18px; height: 18px; flex: 0 0 auto; margin-top: 1px; color: var(--green-dark); }
.pedido-confia strong { display: block; font-size: 13.5px; color: var(--green-dark); }
.pedido-confia span { display: block; font-size: 12.5px; line-height: 1.45; color: var(--muted); }
/* Pagar não é sítio para criar outro CV: o «+» sai dos ecrãs de pagamento.
   Especificidade acima de `.app-area .fab-criar`, que aparece mais abaixo. */
.app-area.sem-fab .fab-criar { display: none; }

.center-card { text-align: center; max-width: 560px; margin: 52px auto; }
.login-card { max-width: 400px; margin: 52px auto; }

/* ---------- Admin ---------- */
/* A cabeça de uma página da área: a mesma abertura em todo o lado — 26px do topo, 22px até ao
   bloco seguinte, 18px entre o texto e as acções. É a medida do painel do candidato
   (`.dash-hello`), que ele deu por boa; a das empresas estava a 0px do topo e com 18px/10px. */
.admin-head { display: flex; justify-content: space-between; align-items: center; margin: 26px 0 22px; flex-wrap: wrap; gap: 18px; }

/* O botao do cabecalho da gestao fica a direita mesmo com texto comprido. Com
   `flex-wrap: wrap` e um `div` que nao encolhe, o texto ocupava a linha toda e o
   botao caia para baixo, encostado a esquerda — diferente de ecra para ecra,
   conforme o comprimento da frase. Com `min-width: 0` o texto encolhe e quebra
   dentro do seu espaco. */
.admin-head > div { flex: 1 1 0; min-width: 0; }
.admin-head > .btn { flex: 0 0 auto; }

.admin-head h1 { margin: 0; }

/* O TÍTULO DE UMA PÁGINA DA ÁREA: uma letra e um tamanho, num sítio só.
   Era o tamanho do casco que calhasse à página — medido no Chrome, as páginas das empresas
   (`.admin-head`) davam 26px e o candidato andava com 26, 31, 34 e 36px conforme o casco
   (`.dash-hello`, `.dash-title`, `.order-head`, `.cat-head`). Ele pediu a mesma letra e o mesmo
   tamanho em tudo: «a mesma letra e tamanho usado nos titulos das paginas empresas sejam iguais
   no /candidato em tudo, afiliado, definições, painel etc». A régua é a das empresas.
   ⚠️ Se um casco precisar de outro tamanho, é AQUI que se muda — uma declaração `font-size`
   num casco abaixo desta linha ganha-lhe por vir depois. */
.admin-head h1,
.cat-head h1,
.dash-hello h1,
.dash-title,
.order-head h1,
.pedido-h {
  font-family: var(--font-display);
  font-size: 26px;
  letter-spacing: -0.6px;
  line-height: 1.08;
}
/* O título não traz margem: a folga até à descrição é SÓ da descrição (7px, abaixo). O `h1` do
   `.order-head` trazia a margem do navegador (0,67em = 17,42px) porque a regra dele só dizia
   `margin-bottom` — era isso que punha o perfil e o afiliado a abrir 8,6px abaixo dos painéis. */
.admin-head h1,
.cat-head h1,
.dash-hello h1,
.dash-title,
.order-head h1 { margin: 0; }
/* O ecrã do pedido é uma coluna estreita e mantém a folga que tinha para o subtítulo. */
.pedido-h { margin-top: 0; }
.stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 20px; }
.stat { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 16px; box-shadow: var(--shadow); }
.stat span { display: block; color: var(--muted); font-size: 12.5px; text-transform: uppercase; letter-spacing: 0.5px; font-weight: 700; margin-bottom: 6px; }
.stat strong { font-size: 30px; line-height: 1.1; font-family: var(--font-display); display: block; }
.stat-meta { display: block; font-style: normal; color: var(--muted); font-size: 13px; margin-top: 4px; }
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.cfg-key { display: block; color: var(--muted); font-size: 11.5px; font-family: var(--font-mono); margin-top: 2px; }
.cfg-input {
  width: 220px;
  padding: 8px 10px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 13.5px;
  font-family: var(--font-mono);
  color: var(--ink-900);
  background: #fff;
  box-sizing: border-box;
}
.cfg-input:focus { outline: none; border-color: var(--green); box-shadow: 0 0 0 3px rgba(14, 138, 94, 0.14); }
table[data-cards] .cfg-input { width: 240px; }
/* Um parâmetro OBRIGATÓRIO vazio (o número que recebe o pagamento) fica a
   vermelho: é o que impede o site de pedir dinheiro sem dizer para onde. A linha
   toda acende, não só o rótulo, para se ver na lista sem ler. */
tr.cfg-falta .cfg-input { border-color: #f5c6c0; background: #fff8f7; }
tr.cfg-falta .cfg-input:focus { border-color: var(--red); box-shadow: 0 0 0 3px rgba(179, 38, 30, 0.12); }
tr.cfg-falta .badge { margin-top: 6px; }
.cfg-actions { margin-top: 16px; display: flex; justify-content: flex-end; }
@media (max-width: 1020px) {
  table[data-cards] .cfg-input { width: 100%; }
  .cfg-actions { justify-content: stretch; }
  .cfg-actions .btn { width: 100%; }
}
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line); vertical-align: middle; }
th { font-size: 11px; text-transform: uppercase; letter-spacing: 0.6px; color: var(--muted); font-family: var(--font-display); }
tr:last-child td { border-bottom: 0; }
/* Os botões que vivem dentro de um formulário numa linha de tabela (ligar/desligar
   uma província): o formulário não pode partir a linha. */
.linha-form { display: inline; }

.actions-cell { display: flex; gap: 8px; flex-wrap: nowrap; align-items: center; }
.inline-form { margin: 0; }
.actions-cell .inline-form,
.copy-row .copy-link-btn { display: flex; }
.actions-cell .inline-form .btn {
  flex: 0 0 auto;
  width: 110px;
  height: 34px;
  box-sizing: border-box;
}
.copy-row { display: flex; gap: 6px; align-items: center; justify-content: center; }
.copy-row input { width: 240px; font-size: 12.5px; color: var(--muted); font-family: var(--font-mono); }

/* Dashboard tables desktop e mobile */
table[data-cards] td,
table[data-cards] th { white-space: nowrap; padding: 9px 8px; vertical-align: top; }
table[data-cards] .copy-row input { width: 210px; font-size: 12px; }
@media (max-width: 1020px) {
  table[data-cards] thead { display: none; }
  table[data-cards],
  table[data-cards] tbody {
    display: flex;
    flex-direction: column;
    gap: 14px;
  }
  table[data-cards] tr {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px 14px;
    padding: 14px;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: var(--card);
  }
  table[data-cards] td {
    display: flex;
    flex-direction: column;
    gap: 3px;
    border: 0;
    padding: 0;
    min-width: 0;
    /* Sem isto o `nowrap` da regra de base sobrevive ao empilhamento e o texto
       longo (a autorizacao, um email) sai cortado a meio da palavra. */
    white-space: normal;
    overflow-wrap: anywhere;
  }
  table[data-cards] td[data-label]::before {
    content: attr(data-label);
    font-size: 11px;
    font-family: var(--font-display);
    text-transform: uppercase;
    letter-spacing: .3px;
    color: var(--muted);
    margin-bottom: 2px;
  }
  table[data-cards] td[data-label="Ações"] { grid-column: 1 / -1; }
  table[data-cards] td[data-label="Link"]  { grid-column: 1 / -1; }
  table[data-cards] .actions-cell { flex-direction: row; flex-wrap: wrap; gap: 8px; }
  table[data-cards] .actions-cell .btn { width: auto; flex: 1 1 auto; }
  table[data-cards] .copy-row { flex-direction: column; align-items: flex-start; gap: 4px; }
  table[data-cards] .copy-row input { width: 100%; font-size: 11px; }
}

/* ---------- Dashboard de templates ---------- */
.stat-sub { display: block; font-size: 12px; color: var(--muted); margin-top: 2px; }
.dash-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px; }
@media (max-width: 720px) { .dash-grid { grid-template-columns: 1fr; } }
.top-row { display: flex; align-items: center; gap: 12px; padding: 9px 0; border-bottom: 1px dashed var(--line); }
.top-row:last-child { border-bottom: 0; }
.top-rank {
  width: 26px; height: 26px; border-radius: 8px;
  display: grid; place-items: center;
  background: var(--ink-950); color: #fff;
  font-family: var(--font-mono); font-size: 12.5px;
}
.top-row:nth-child(2) .top-rank { background: var(--gold); }
.top-main { flex: 1; display: flex; flex-direction: column; line-height: 1.25; }
.top-main strong { font-size: 14px; color: var(--ink-950); }
.top-main small { font-size: 11.5px; color: var(--muted); }
.top-count { font-family: var(--font-mono); font-size: 12.5px; color: var(--green-dark); white-space: nowrap; }
.swatches { display: inline-flex; gap: 3px; margin-right: 8px; vertical-align: middle; }
.swatch { width: 12px; height: 12px; border-radius: 50%; display: inline-block; border: 1px solid rgba(0,0,0,0.12); }
.td-right { text-align: right; }
.td-actions { white-space: nowrap; }

.autosave-status {
  font-size: 12.5px;
  font-family: var(--font-mono);
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.autosave-status::before {
  content: "";
  width: 8px; height: 8px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 auto;
}
.autosave-status.busy::before { background: var(--gold); animation: pulse 1s infinite; }
.autosave-status.ok::before { background: var(--green-dark); }
.autosave-status.err { color: #b3261e; }
.autosave-status.err::before { background: #b3261e; }
.sticky-spacer { flex: 1; }
.sticky-right { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }
.req { color: #b3261e; font-style: normal; }
.req-feedback { font-size: 12px; color: var(--muted); max-width: 340px; text-align: right; line-height: 1.4; }
.req-feedback strong { color: #b3261e; }
.req-feedback:empty { display: none; }
/* A variante `.warn` — a pastilha amarela «Falta: …» — foi com a carta: o que
   falta passou a estar marcado no próprio campo, em `letter.html`. O editor do
   CV (`resume.html`, `refreshRequired` em static/app.js) continua a escrever
   aqui, mas só em texto simples. */

/* ---------- Realce dos [parênteses rectos] no corpo ----------
   Um `textarea` não estiliza partes do texto, por isso o realce é um
   `div` espelhado POR BAIXO do textarea (mesma fonte, mesmo padding, mesma
   largura de linha): o textarea é transparente no fundo e o div pinta os
   `[...]` a amarelo. É a técnica dos editores de código (highlight atrás do
   input). Se as métricas divergirem, o realce desalinha — por isso as duas
   camadas partilham a MESMA classe de fonte e o mesmo padding. */
.body-wrap { position: relative; }
/* O textarea é inline por default: o wrap ficava 7px mais alto que ele (o
   descender da linha) e o espelho (inset:0) media 284px contra 277 — o realce
   descia 7px e as linhas partiam em sítios diferentes. display:block mata o
   gap de baseline. */
.body-wrap textarea { display: block; }
.body-highlight {
  position: absolute;
  inset: 0;
  padding: 11px 13px;
  /* A MESMA border do textarea (transparente): o textarea é border-box, logo o
     padding efectivo dele é 11-1.5=9.5px. Sem a border aqui, o espelho tinha
     9.5px a mais de texto por linha e as linhas partiam em sítios diferentes
     (medido: 284px vs 277px de altura, 10px de scrollHeight). */
  border: 1.5px solid transparent;
  font-size: 15px;
  font-family: inherit;
  /* O MESMO line-height do textarea (que não o define: fica «normal»). Um
     valor diferente desalinha o realce linha a linha — medido: 21.75px vs
     normal. */
  line-height: normal;
  color: transparent;
  white-space: pre-wrap;
  word-wrap: break-word;
  overflow: hidden;
  pointer-events: none;
  border-radius: var(--radius-sm);
}
.body-highlight mark {
  background: #fdf3d7;
  color: #6b5410;
  border-radius: 3px;
  /* SEM padding e SEM box-shadow: qualquer métrica a mais muda onde a linha
     parte e o realce desalinha do texto (medido: 10px de diferença de
     scrollHeight com padding+shadow). O fundo amarelo sozinho marca bem. */
  box-shadow: none;
}
/* O textarea fica transparente para o realce se ver; o caret continua a
   pintar-se (é do browser, não do background). */
#body { background: transparent; }
#body::selection { background: rgba(14, 138, 94, 0.22); }
.btn.is-disabled {
  opacity: 0.55;
  pointer-events: none;
  filter: grayscale(0.4);
}
@media (max-width: 720px) {
  .sticky-right { flex-direction: column; align-items: flex-start; gap: 8px; }
  .req-feedback { text-align: left; max-width: 100%; }
}
@keyframes pulse { 50% { opacity: 0.35; } }

.checkout-grid {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: 24px;
  /* `start` e não `stretch`: os dois cartões não têm de acabar à mesma altura.
     Esticados, o mais alto (o do documento, preso ao tecto do quadro) mandava no
     outro e o formulário ganhava um fundo branco por baixo dos botões — medido a
     1280px: os botões acabavam aos 621px e o cartão ia até aos 867px, 246px de
     nada. Cada cartão acaba agora no seu próprio conteúdo, mais o padding. */
  align-items: start;
}
@media (max-width: 860px) {
  .checkout-grid { grid-template-columns: 1fr; }
  /* Empilhado, o preview vem PRIMEIRO: o documento é o que se está a comprar, e
     é assim que ele aparece no computador (aberto, à esquerda).
     Isto já foi ao contrário, e por medição: o preview é uma imagem que chega
     tarde (o PNG é gerado no servidor) e, ao chegar, empurrava o botão «Gerar
     pedido» 366px para baixo num iPhone — o primeiro toque caía onde ele ainda
     estava. As duas defesas que devolveram a ordem pedida:
     (a) o quadro da pré-visualização tem altura FIXA aqui (62vh), portanto a
         imagem não empurra nada quando chega;
     (b) as acções ficam no fim do formulário, no sítio normal (chegou a haver uma
         barra presa ao fundo; o dono do produto mandou tirar o fundo e ela saiu
         com ele).
     A defesa que tranca isto e' (a): se a altura reservada sair, MEDIR outra vez o
     desvio do botão antes de dar a ordem como boa. */
  .checkout-grid .preview-card { order: 1; }
  .checkout-grid .checkout-form-card { order: 2; }
  .preview-frame {
    height: 62vh;
    min-height: 320px;
    overflow: hidden;
  }
  .preview-frame img,
  .preview-frame iframe {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top center;
  }
}
.preview-card { display: flex; flex-direction: column; }
.preview-card h2 { margin-bottom: 12px; }
.preview-frame {
  position: relative;
  flex: 1;
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: auto;
  background: #f4f4f6;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  max-height: 600px;
  padding: 18px;
}
/* No computador o tecto do quadro acompanha a janela em vez de reservar 600px à
   força, para um portátil baixo não ter a página a rolar só por causa do quadro.
   Não esconde nada: o documento rola DENTRO do quadro, e é o que o cliente já faz
   (o CV tem 953px de altura num quadro que não passa dos 600). Em telemóvel fica
   como estava — lá a altura é fixa de propósito, e o comentário do
   `@media (max-width: 860px)` explica porquê. */
@media (min-width: 861px) {
  .preview-frame { max-height: clamp(380px, calc(100vh - 260px), 600px); }
}
.preview-frame img {
  display: block;
  width: 340px;
  height: auto;
  background: #fff;
  box-shadow: 0 1px 10px rgba(15, 15, 20, 0.12);
  user-select: none;
  -webkit-user-drag: none;
}
/* O preview da CARTA é um <iframe> com o PDF — sem regra, o browser dá-lhe
   300×150 (o tamanho por omissão) e o PDF renderiza «meia página». A folha
   A4 na mesma largura do img: 340 × (297/210) ≈ 481px. `flex-shrink: 0`
   porque o `.preview-frame` é flex e encolhia o iframe para 304px. */
.preview-frame iframe {
  display: block;
  width: 340px;
  aspect-ratio: 210 / 297;
  height: auto;
  flex-shrink: 0;
  border: 0;
  background: #fff;
  box-shadow: 0 1px 10px rgba(15, 15, 20, 0.12);
}
@media (max-width: 520px) {
  .preview-frame img { width: 100%; }
  .preview-frame iframe { width: 100%; }
}
.preview-frame::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  box-shadow: inset 0 0 0 0 transparent;
  pointer-events: none;
}
.small { font-size: 12px; }

/*** Galeria de CVs: um cartão A4 por CV ***/
/* Grelha ELÁSTICA (auto-fill), de propósito: ao contrário de uma listagem, aqui não há
   células a alinhar entre linhas — cada cartão é uma caixa inteira. Um mínimo de 240px
   dá cartões grandes (a tiragem A4 lê-se mesmo como um documento) e quebram sozinhos:
   1 coluna aos 390px, 2 a ~620px, 3-4 num portátil, sem breakpoints. */
.cvs-grid {
  display: grid;
  /* Sem isto o cartão estica até à altura da linha (a célula «Criar novo CV» é alta)
     e a sobreposição do nome caía FORA da folha. */
  align-items: start;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 20px 18px;
  margin-top: 26px;
  padding: 2px 0 6px;
}
/* Em ecrã estreito o mínimo de 240px dava UMA coluna de cartões gigantes (334px de
   largura, 523 de altura a 390px). Com 150px cabem dois por linha — a tiragem A4
   (aspect-ratio) encolhe proporcional e o cabeçalho do CV continua a ler-se. */
@media (max-width: 560px) {
  /* Dois por linha, como o Jobseeker: o cartão é a FOLHA — uma borda, nada de
     caixa em volta. O nome e o «editado há» ficam por baixo, fora da folha. */
  .cvs-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px 12px; }
  .cv-card { background: transparent; border: 0; border-radius: 0; box-shadow: none; }
  .cv-card-shot { padding: 0; background: transparent; border-radius: 0; }
  .cv-shot { border: 1px solid var(--line); border-radius: 6px; box-shadow: 0 2px 8px rgba(13, 20, 32, 0.10); }

  .cv-name { font-size: 15px; line-height: 1.2; }
  .cv-edited, .cv-card-meta { font-size: 12px; }
}
/* O «+» sai da barra e flutua à direita em toda a área do candidato. A barra fica
   só com os destinos, repartidos por igual: um item ao meio, dois lado a lado. */
.fab-criar { display: none; }
@media (max-width: 900px) {
  .app-area .app-baixo { justify-content: center; }
  .app-area .app-baixo-mais-wrap { display: none; }
  .app-area .app-baixo-lado { flex: 0 0 auto; display: flex; align-items: center; gap: 4px; }
  .app-area .app-baixo-item { flex: 0 0 auto; padding: 4px 16px; }
  .app-area .fab-criar {
    display: inline-flex; align-items: center; justify-content: center;
    position: fixed; right: calc(16px + env(safe-area-inset-right));
    bottom: calc(74px + env(safe-area-inset-bottom));
    width: 56px; height: 56px; border-radius: 50%;
    background: var(--green); color: #fff;
    box-shadow: 0 10px 24px rgba(14, 138, 94, 0.38); z-index: 45;
    text-decoration: none;
  }
  .app-area .fab-criar svg { width: 26px; height: 26px; }
}
/* O cartão NÃO pode ter `overflow: hidden`: o menu «⋯» abre 180px para a ESQUERDA a
   partir de um botão que está a ~40px da borda, e num cartão de duas colunas (~170px
   a 560px) isso é ~218px — o menu saía cortado a ESQUERDA pela metade (medido: só
   ~120px visíveis). O corte dos cantos redondos passa a ser de cada zona (a tiragem
   em cima, o corpo em baixo), que é o que o `overflow: hidden` do cartão fazia. */
.cv-card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  position: relative;
  border-radius: 14px;
  background: transparent;
  border: 0;
  box-shadow: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.cv-card:hover { border-color: var(--green); box-shadow: 0 14px 30px -20px rgba(13, 20, 32, 0.45); }
/* A cria na galeria: a MESMA `.cv-card` (mesmas dimensões), vazia — tracejado e o
   convite. É como no painel de controlo: criar deixou de ser botão verde no topo. */
.cv-card-new { background: transparent; border-style: dashed; border-color: var(--line-strong); box-shadow: none; }
/* O cartão «criar» é um `<a>` inteiro: sem isto herda o azul sublinhado do browser
   e o convite lê-se como uma hiperligação de 1999, ao lado de cartões com o texto
   da casa. */
a.cv-card-new, a.cv-card-new:visited { color: var(--ink); text-decoration: none; }
.cv-card-new .cv-card-shot { background: transparent; }
a.cv-card-new:hover { border-color: var(--green); box-shadow: none; }
/* Os cantos redondos do cartão, agora por zona: a tiragem em cima (14px do cartão
   menos 1.5px da borda) e o corpo em baixo. O que o `overflow: hidden` do cartão
   segurava — e que o menu «⋯» precisa de largar. */
.cv-card-shot {
  padding: 0;
  background: transparent;
  border-radius: 12.5px 12.5px 0 0;
  overflow: hidden;
  /* A altura é da caixa, não da imagem: sem isto um PNG com outra proporção
     esticava o cartão e o nome/«Editado há…» (que são absolutos) caíam em cima
     do CV, a meio da folha. */
  aspect-ratio: 210 / 297;
}
/* A proporção A4 é o que faz o cartão ler-se como um CV. `object-position: top` garante
   que, se um dia a imagem vier com outra proporção, se vê sempre o cabeçalho do CV. */
.cv-shot {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top;
  border: 1px solid var(--line);
  border-bottom: 0;
  border-radius: 6px 6px 0 0;
  background: #fff;
}
.cv-shot-empty { background: var(--line); }
/* A galeria mostra a carta como miniatura em PNG (letter_preview_png), igual
   ao CV — o bloco de texto com riscas que aqui vivia saiu: ao lado dos CVs
   parecia um template antigo. O mock da landing tem o seu próprio desenho
   (.prod-shot-letter, mais abaixo). */
/* Havia aqui um selo «carta» a seguir ao nome, e saiu: na galeria das cartas
   TODOS os cartões são cartas, e o nome («Carta — Banco BAI») já o diz. Era a
   mesma palavra três vezes — no menu, no nome e no selo. */
/* O documento volta a ser clicável: o link envolve a tiragem e leva ao mesmo sítio do
   título (edição, ou pagamento se estiver por pagar). */
.cv-shot-link { display: block; }
.cv-shot-link:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; border-radius: 6px; }
.cv-card-body {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  flex: 1 1 auto;
  /* O texto encosta à tiragem: o nome e o «Editado há…» lêem-se como legenda
     do CV, não como um bloco à parte. */
  padding: 8px 12px 8px;
  border-radius: 0 0 12.5px 12.5px;
  overflow: hidden;
}
/* O tempo de edição relativo vai debaixo do título, como no jobseeker: «Editado há 2 dias». */
.cv-edited { font-size: 12px; color: var(--muted); }
/* Estado "por pagar": sem badge — a ênfase é o CTA "Concluir pagamento". */
/* Duas linhas fixas, não uma. As cartas têm títulos muito mais longos que os CVs
   («Carta de apresentação para a Empresa X» vs «Curriculum Vitae 1»): com uma só
   linha + reticências perdia-se mais de metade do nome. Com `line-clamp: 2` o
   texto aproveita as duas linhas e, como todas as caixas ficam com a mesma altura,
   o tempo de edição e os botões do pé alinham entre cartões mesmo havendo parágrafo
   no texto. O `min-height` garante a altura da 2.ª linha mesmo nos títulos curtos. */
.cv-name {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  line-height: 1.36;
  min-height: 2.72em;
  max-width: 100%;
  font-weight: 700;
  color: var(--ink-900);
  text-decoration: none;
  overflow: hidden;
  overflow-wrap: anywhere;
}
a.cv-name:hover { text-decoration: underline; text-underline-offset: 3px; }
/* A contagem junto ao título, para o filtro escolhido se ler de longe. */
.cv-total {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 20px;
  padding: 0 7px;
  margin-left: 8px;
  border-radius: 999px;
  background: var(--green-soft);
  color: var(--green-dark);
  font-size: 12px;
  font-weight: 700;
  vertical-align: middle;
}
/* O pé do cartão da galeria: os três botões visíveis, como no Jobseeker — a ação
   principal estica (Editar / Concluir pagamento / Descarregar PDF / Renovar) e os dois
   atalhos de ícone (Pré-visualizar e Apagar) fecham a linha. */
.cv-card-foot {
  display: flex;
  align-items: center;
  gap: 6px;
  /* Mais folga em baixo: o botão estava a tocar a borda do cartão. */
  padding: 0 12px 16px;
}
/* Um SVG dentro do botão não tem medida própria: sem isto estica até ao tamanho
   do browser (o `.btn` é `inline-flex` com `gap`, dá-lhe o lugar, não o tamanho). */
.cv-cta svg { width: 16px; height: 16px; flex: 0 0 auto; }
.cv-cta {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* «Por pagar» não é uma entrega: é o que falta fazer. Fica âmbar, a cor de
   aviso do site, para não se confundir com o verde de «Descarregar». */
.cv-cta.is-pending {
  background: #fff6e5;
  color: #8a5300;
  border: 1px solid #f2d9a6;
  box-shadow: none;
}
.cv-cta.is-pending:hover { background: #ffefd2; color: #6f4300; }
.cv-mini { flex: 0 0 auto; }
.cv-mini-form { display: flex; margin: 0; flex: 0 0 auto; }
/* O menu «⋯» do cartão: as ações secundárias (Pré-visualizar, Duplicar, Apagar)
   vivem num dropdown — o mesmo padrão `.head-dropdown` da navbar, com escopo
   `.cv-menu` para não tocar na nav. Abre para a ESQUERDA (o botão está no canto
   direito do cartão, junto à borda da grelha) e POR CIMA do cartão. O `right` é
   do BOTÃO e não do cartão: fica 12px+1.5px para dentro da borda, o que lê como
   alinhado com o resto do pé. */
.cv-menu { flex: 0 0 auto; }
.cv-menu .cv-menu-btn { cursor: pointer; }
.cv-menu .cv-menu-list {
  top: auto;
  bottom: calc(100% + 6px);
  right: 0;
  /* `min(180px, …)`: o menu nunca fica mais largo que o ecrã, por estreito que ele
     esteja. Com `min-width: 180px` fixo, abaixo de ~204px de viewport o menu
     começava em coordenadas negativas — e o `overflow-x: clip` do topo tornava-o
     inalcançável. */
  min-width: min(180px, calc(100vw - 24px));
  max-width: calc(100vw - 24px);
}
.cv-menu .cv-menu-list .link {
  width: 100%;
  border: 0;
  background: none;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  appearance: none;
  color: var(--ink-900);
}
.cv-menu .cv-menu-list .cv-menu-danger { color: var(--red); }
.cv-menu .cv-menu-list .cv-menu-danger:hover { background: #fdeceb; color: var(--red); }
.cv-menu-form { margin: 0; }
/* O cartão É a folha: o nome, o «editado há» e a acção assentam sobre os últimos
   centímetros dela (brancos num CV), com degrau para branco. Vale igual no
   computador e no telemóvel — pedido do dono: «isso também se aplica a desktop». */
.cv-card:not(.cv-card-new) { position: relative; }
.cv-card:not(.cv-card-new) .cv-card-shot { position: relative; }
.cv-card:not(.cv-card-new) .cv-card-body {
  position: absolute; left: 0; right: 0; bottom: 50px;
  padding: 26px 12px 4px; gap: 1px;
  /* `column`, não `column-reverse`: a leitura é nome → «editado» → barra. Antes
     a data ficava por cima do nome, que é a informação de segunda a abrir o
     bloco. */
  display: flex; flex-direction: column; align-items: flex-start;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.92) 45%, #fff 100%);
}
.cv-card:not(.cv-card-new) .cv-card-foot {
  position: absolute; left: 0; right: 0; bottom: 0;
  /* 16px, não 12: o botão estava a tocar a borda do cartão. */
  padding: 0 12px 16px; background: #fff; gap: 6px;
}
.cv-card:not(.cv-card-new) .cv-cta { flex: 1 1 auto; }

/* O pé e o corpo foram apertados: o nome, a data e o botão pareciam três coisas
   soltas com ar entre elas. Agora o nome encosta ao «editado», a barra fecha o
   bloco e o botão assenta a 12px da base. */
.cv-card:not(.cv-card-new) .cv-card-body { padding: 18px 12px 0; gap: 2px; }
/* O nome reservava SEMPRE duas linhas (min-height: 2.72em) para alinhar as
   datas entre cartões na lista. No cartão da galeria o bloco está ancorado em
   baixo, por isso essa reserva não alinha nada: só abria um vão entre o nome e
   «Editado há…». Aqui o nome ocupa as linhas que precisa. */
.cv-card:not(.cv-card-new) .cv-name { min-height: 0; }
.cv-card:not(.cv-card-new) .cv-card-foot { padding: 0 10px 12px; gap: 8px; }
.cv-cta { display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
.cv-cta svg { width: 14px; height: 14px; flex: none; }
.cv-dot { margin: 0 5px; opacity: 0.45; }

/* A barra do preenchimento: 3px, sempre a toda a largura do texto. Cheia é um CV
   completo; a um terço diz «ainda não acabaste» sem gastar outra frase. */
.cv-progress {
  width: 100%; height: 3px; margin-top: 6px;
  border-radius: 999px; background: rgba(12, 30, 22, 0.09); overflow: hidden;
}
.cv-progress span { display: block; height: 100%; border-radius: 999px; background: var(--green); }
.cv-card.is-empty .cv-progress { display: none; }

/* O CV por começar: uma folha por escrever, não a miniatura de uma folha em
   branco (que saía como uma faixa azul e lia-se como avaria). */
.cv-card.is-empty .cv-card-shot {
  background: #fbfaf6;
  border: 1px dashed var(--line);
  border-radius: 12px;
}
.cv-shot-nova {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; width: 100%; height: 100%;
  color: var(--muted); text-decoration: none;
}
.cv-shot-nova svg { width: 30px; height: 30px; color: var(--green-dark); opacity: 0.75; }
.cv-shot-nova span { font-size: 12px; letter-spacing: 0.01em; }
.cv-card.is-empty .cv-name { color: var(--muted); font-weight: 600; }

/* A célula «Criar novo CV»: uma folha tracejada com o «+» e o convite AO CENTRO —
   igual no computador e no telemóvel. Antes, no computador, o texto caía fora do
   tracejado. */
.cvs-grid .cv-card-new {
  /* O tracejado é o CARTÃO, e o «+» com o texto ficam centrados na folha —
     antes o convite estava encostado à base e a folha parecia vazia em cima. */
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12px; padding: 20px;
  border: 1.5px dashed var(--line-strong); border-radius: 12px;
  background: transparent; aspect-ratio: 210 / 297; position: relative;
}
/* `display: contents`: a caixa da miniatura desaparece e o «+» e o corpo passam a
   ser filhos do cartão, que é quem centra. */
.cvs-grid .cv-card-new .cv-card-shot { display: contents; }
.cvs-grid .cv-card-new .cv-mais { display: flex; color: var(--green-dark); }
.cvs-grid .cv-card-new .cv-mais svg { width: 46px; height: 46px; stroke: currentColor; stroke-width: 1.6; }
.cvs-grid .cv-card-new .cv-card-body {
  position: static; padding: 0; text-align: center; background: transparent;
  display: block; left: auto; right: auto; bottom: auto;
  /* `flex: 0` porque o corpo é item flex e, com `flex: 1`, esticava até ao fim
     da folha: o texto ficava no topo de uma caixa invisível de 264px e o «+»
     parecia encostado ao canto. */
  flex: 0 0 auto;
}
.cvs-grid .cv-card-new .cv-name { font-size: 15px; }
.cvs-grid .cv-card-new .cv-card-meta { display: block; font-size: 12px; color: var(--muted); margin-top: 4px; }

.cv-card:has(.cv-menu-list.open) { z-index: 30; }
/* O badge «Por pagar» no corpo do cartão: o estado à vista sem precisar de
   espaço no pé (o «Concluir pagamento» inteiro não cabia ao lado de três
   ícones num cartão de 167px — medido). */
/* Em ecrã estreito (2 colunas de ~170px) o CTA fica com 24px depois de três
   ícones de 34px — até «Editar» corta (medido a 404px). Os ícones encolhem
   para 28px e o gap para 4px: sobram ~54px para o CTA, e «Editar» / «Por
   pagar» cabem. */
@media (max-width: 560px) {
  .cv-card-foot { gap: 4px; padding: 0 10px 10px; }
  .cv-card-foot .icon-btn { width: 28px; height: 28px; }
  .cv-card-foot .icon-btn svg { width: 14px; height: 14px; }
  .cv-cta { padding: 7px 8px; }
  /* O dropdown estica pelo resto do pé e o CTA deixa de esticar (já tem elipse):
     é o CTA que cede o espaço quando os ícones não cabem. O MENU, esse, continua
     ancorado ao BOTÃO — ver o `right: 0` da regra de base, que vale a toda a
     largura. ⚠️ Não se reintroduza aqui um `left: 0` para o menu: o botão «⋯» está
     no canto DIREITO tanto do cartão da galeria como da linha do painel, e o
     `right: 0` é o que o joga para a ESQUERDA, que é de onde há espaço. Aberto
     para a direita, saía do ecrã nos dois: no cartão a 480px de viewport o menu
     ficava 100px fora, e na linha do painel a 533px ficava em 467..647 — 114px
     fora, com as três acções («Editar», «Pré-visualizar», «Apagar») ilegíveis. */
  .cv-cta { flex: 0 1 auto; }
  .cv-card-foot .cv-menu { flex: 1 1 auto; min-width: 0; justify-content: flex-end; }
}
/* Aos 280px (Galaxy Fold) "Anterior + página + Seguinte" já não cabe na linha
   e o "Seguinte" saía do cartão: parte em duas. */
@media (max-width: 380px) {
  .pager { flex-wrap: wrap; }
}
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: 1.5px solid transparent;
  border-radius: 9px;
  background: transparent;
  color: var(--ink-700);
  cursor: pointer;
  text-decoration: none;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.icon-btn:hover { background: var(--line); border-color: var(--line); color: var(--ink-900); }
.icon-btn svg { width: 16px; height: 16px; display: block; }
.icon-danger { color: var(--red); }
.icon-danger:hover { background: #fdeceb; border-color: #f3c9c6; color: var(--red); }

/*** Modal de pré-visualização ***/
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(13, 20, 32, 0.62);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 90;
  padding: 18px;
}
.modal-backdrop[hidden] { display: none; }
.modal-card {
  background: var(--card);
  border-radius: 14px;
  max-width: 430px;
  width: 100%;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.28);
  overflow: hidden;
}
.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 18px 0;
  gap: 12px;
}
.modal-head h3 { font-size: 17px; margin: 0; }
.modal-close {
  border: 0;
  background: transparent;
  font-size: 19px;
  line-height: 1;
  cursor: pointer;
  color: var(--muted);
  padding: 4px;
}
.modal-close:hover { color: var(--ink-900); }
.modal-body {
  padding: 12px 18px 18px;
  overflow: auto;
}
.modal-body .preview-frame {
  max-height: 58vh;
  min-height: 300px;
  padding-top: 30px;
}

/* ── O pop da importação com IA ───────────────────────────────────────────────────────────────
   Aparece por cima do editor quando o CV acabou de nascer de um ficheiro: o editor já abriu com o
   que o parser leu (0,10 s) e aqui vive o que a IA tem para dizer (5 a 8 s). Três estados: a ler,
   o resultado, não correu.

   Desenho (Out/2026, a pedido dele — «utilizadores querem coisas directas»): um cartão ESTREITO e
   empilhado, com uma decisão só (o interruptor) e uma acção só (o botão). A versão anterior tinha
   duas colunas, dois cartões de texto e cinco cartões de modelo com nome, preço e etiqueta cada —
   era um formulário dentro de um pop. Agora: três defeitos à vista (o resto atrás de «ver o resto»),
   o estilo numa linha que muda ao tocar na miniatura, e o «deixar como está» como link discreto.

   O ✕ e o fundo escuro fecham; no telemóvel o cartão sobe de baixo como uma folha, que é o gesto
   que se espera num telefone. */
.imp-pop {
  position: fixed; inset: 0; z-index: 95;
  display: flex; align-items: center; justify-content: center;
  padding: 18px; background: rgba(13, 20, 32, .66);
}
.imp-pop[hidden] { display: none; }
.imp-card {
  position: relative; width: 100%; max-width: 520px; max-height: 92vh; overflow: auto;
  background: var(--card); border-radius: 18px; box-shadow: var(--shadow-lift);
  padding: 24px 24px 20px;
}
.imp-estado { display: none; }
.imp-pop[data-estado="carregar"] .imp-estado--carregar,
.imp-pop[data-estado="resultado"] .imp-estado--resultado,
.imp-pop[data-estado="falhou"] .imp-estado--falhou,
.imp-pop[data-estado="pronto"] .imp-estado--pronto { display: block; }
.imp-titulo { margin: 0; font-family: var(--font-display); font-size: 21px; line-height: 1.25; color: var(--ink-900); }
.imp-sub { margin: 7px 0 0; color: var(--muted); font-size: 14px; }
.imp-head { display: flex; align-items: flex-start; gap: 12px; }
.imp-head .imp-titulo { flex: 1 1 auto; }
.imp-x {
  flex: none; border: 0; background: transparent; cursor: pointer;
  font-size: 17px; line-height: 1; padding: 4px 6px; border-radius: 8px; color: var(--muted);
}
.imp-x:hover { background: var(--paper-soft); color: var(--ink-900); }

/* A "leitura": três traços que respiram. Não é uma barra de progresso — não há progresso para
   mostrar (a chamada à IA é uma só); é sinal de vida. Quem pediu menos movimento tem-no desligado
   pela regra global do `prefers-reduced-motion`. */
.imp-ler { display: flex; gap: 6px; margin-bottom: 14px; }
.imp-ler span {
  width: 32px; height: 5px; border-radius: 3px; background: var(--green-soft);
  animation: imp-ler 1.2s ease-in-out infinite;
}
.imp-ler span:nth-child(2) { animation-delay: .16s; }
.imp-ler span:nth-child(3) { animation-delay: .32s; }
@keyframes imp-ler {
  0%, 100% { background: var(--green-soft); }
  50% { background: var(--green); }
}

/* Os passos: os reais. O primeiro já está feito quando o pop abre (o parser leu o ficheiro em
   0,10 s), o segundo é o que demora 5 a 8 s, o terceiro sai da mesma chamada. Uma linha cada —
   a nota por baixo de cada passo era o dobro do texto para a mesma informação. */
.imp-passos { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 12px; }
.imp-passo { display: flex; gap: 11px; align-items: center; }
.imp-marca {
  flex: none; width: 22px; height: 22px; border-radius: 50%;
  border: 1.5px solid var(--line); color: var(--muted);
  display: inline-flex; align-items: center; justify-content: center; font-size: 12px;
}
.imp-passo.is-feito .imp-marca { background: var(--green); border-color: var(--green); color: #fff; }
.imp-passo.is-agora .imp-marca { border-color: var(--green); }
.imp-spin {
  width: 10px; height: 10px; border-radius: 50%;
  border: 2px solid var(--green-soft); border-top-color: var(--green);
  animation: imp-spin .8s linear infinite;
}
@keyframes imp-spin { to { transform: rotate(360deg); } }
.imp-passo b { font-size: 14.5px; font-weight: 600; color: var(--ink-900); }
.imp-passo:not(.is-feito):not(.is-agora) b { color: var(--muted-light); font-weight: 500; }

/* O relógio da espera. Discreto e numérico: o que a pessoa quer saber, ao fim de 20 s, é que
   alguma coisa continua a andar — e quanto tempo já lá vai. */
.imp-relogio {
  margin-left: 1px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px; font-weight: 500; letter-spacing: .3px; color: var(--muted-light);
  font-variant-numeric: tabular-nums;
}

.imp-resumo { margin: 14px 0 0; font-size: 14.5px; color: var(--ink-700); }
.imp-problemas { margin: 8px 0 0; padding-left: 18px; display: grid; gap: 6px; font-size: 14px; color: var(--ink-700); }
.imp-mais { margin-top: 6px; }
.imp-mais > summary { cursor: pointer; font-size: 13.5px; color: var(--green-dark); }
.imp-mais > .imp-problemas { margin-top: 8px; }
.imp-bloco-titulo {
  margin: 18px 0 7px; font-size: 12px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted-light); font-weight: 600;
}
.imp-falha { margin: 12px 0 0; font-size: 14.5px; color: var(--ink-700); }

/* O estilo: uma linha com o nome e o preço do escolhido, e a fila de miniaturas por baixo. A linha
   escondida por modelo é trocada pelo guião ao tocar na miniatura — o preço daquilo que ele está
   a escolher fica sempre à frente, sem repetir nome e preço cinco vezes. */
.imp-sugestao { margin: 0 0 10px; font-size: 15.5px; color: var(--ink-900); }
.imp-sugestao small { margin-left: 6px; font-size: 13px; color: var(--green-dark); }
.imp-modelos {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(64px, 1fr));
  gap: 8px;
}
.imp-modelo {
  position: relative; min-width: 0; padding: 3px; cursor: pointer;
  border: 1.5px solid var(--line); border-radius: 9px; background: #fff;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.imp-modelo:hover { border-color: var(--line-strong); }
.imp-modelo.is-rec { border-color: var(--green); box-shadow: 0 0 0 2px var(--green-soft); }
.imp-modelo:has(input:checked) { border-color: var(--green); }
.imp-modelo input {
  position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none;
}
.imp-modelo-thumb { display: block; width: 100%; border-radius: 5px; }

/* Uma decisão, um gesto: a caixa nativa (com a cor da casa) em vez de um interruptor desenhado —
   é a mesma coisa com metade do código e o teclado já sabe usá-la. */
.imp-switch {
  display: flex; gap: 11px; align-items: flex-start; cursor: pointer;
  margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--line);
}
.imp-switch input { flex: none; width: 17px; height: 17px; margin: 2px 0 0; accent-color: var(--green); }
.imp-switch b { display: block; font-size: 14.5px; font-weight: 600; color: var(--ink-900); }
.imp-switch small { display: block; margin-top: 2px; font-size: 13px; color: var(--muted); }

.imp-accoes { display: flex; align-items: center; gap: 6px 18px; flex-wrap: wrap; margin-top: 20px; }
.imp-link {
  border: 0; background: transparent; padding: 0; cursor: pointer; font: inherit;
  font-size: 14px; color: var(--muted); text-decoration: underline; text-underline-offset: 3px;
}
.imp-link:hover { color: var(--ink-900); }
.imp-pe { margin: 14px 0 0; }

@media (max-width: 640px) {
  .imp-pop { padding: 0; align-items: flex-end; }
  .imp-card { max-width: none; border-radius: 18px 18px 0 0; max-height: 94vh; padding: 20px 18px 18px; }
  .imp-titulo { font-size: 19px; }
  .imp-accoes { flex-direction: column; align-items: stretch; }
  .imp-accoes .btn { width: 100%; }
  .imp-link { text-align: center; padding: 6px 0; }
}

.checkout-grid .kv {
  padding: 2px 0;
}
.checkout-grid .kv li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 14px;
  padding: 12px 0;
  border-bottom: 1px dashed var(--line);
}
.checkout-grid .kv li:last-child { border-bottom: 0; }
.checkout-grid .kv span {
  color: var(--muted);
  font-size: 13px;
}
.checkout-grid .kv strong {
  text-align: right;
  line-height: 1.5;
  font-weight: 600;
  margin-left: auto;
  flex-shrink: 0;
}
.checkout-grid .kv li.price-discount span,
.checkout-grid .kv li.price-discount strong {
  color: var(--green);
}
.checkout-grid .kv strong.price-total {
  color: var(--ink-950);
  font-weight: 800;
  font-size: 17px;
  letter-spacing: -0.3px;
}
.checkout-grid .kv li.price-total-li {
  border-bottom: 0;
  padding-top: 14px;
}
.ref-box { margin: 18px 0 4px; }
.ref-box label {
  display: block;
  font-weight: 600;
  font-size: 13.5px;
  margin-bottom: 6px;
  color: var(--ink-900);
}
.ref-box label small { color: var(--muted); font-weight: 400; }
.ref-input-row { display: flex; gap: 8px; }
.ref-input-row input {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono);
  text-transform: lowercase;
}
.ref-input-row .btn { flex: 0 0 auto; height: auto; }
.ref-hint { font-size: 12.5px; margin-top: 6px; min-height: 16px; color: var(--muted); }
/* Modelo grátis: substitui os métodos de pagamento, por isso precisa de se
   aguentar sozinho — a caixa é o que separa esta nota do resto. */
.free-note {
  margin: 4px 0 0;
  padding: 14px 16px;
  border: 1px solid rgba(14, 138, 94, 0.28);
  background: rgba(14, 138, 94, 0.07);
  border-radius: 12px;
  color: var(--green-dark);
  font-weight: 600;
  font-size: 14.5px;
  line-height: 1.45;
}
.ref-hint.ok { color: var(--green-dark); font-weight: 600; }
.ref-hint.err { color: #b3261e; }
.checkout-grid form.mt { margin-top: 22px; }
.checkout-grid .field { margin-bottom: 16px; }
.checkout-grid .btn-block { margin-top: 6px; }
/* Os dois botões ficam lado a lado em qualquer largura: «Editar» à esquerda, o
   verde à direita. Empilhá-los no telemóvel punha o «Editar» no meio da página,
   entre o preço e a ação principal. O «Editar» é que encolhe (sem o ícone e com
   menos padding), nunca o verde — que é o que se quer carregar. */
.checkout-actions { display: flex; gap: 10px; margin-top: 6px; align-items: stretch; }
.checkout-actions .btn { flex: 0 0 auto; }
.checkout-actions .btn-block { width: auto; flex: 1 1 auto; margin-top: 0; }

/* ---------- Escolha de método de pagamento ---------- */
.pay-methods { border: 0; padding: 0; margin: 20px 0 4px; }
.pay-methods legend {
  font-weight: 600; font-size: 13.5px; margin-bottom: 8px; color: var(--ink-900);
}
.pay-choice {
  position: relative;
  border: 1.5px solid var(--line);
  border-radius: 12px;
  margin-bottom: 10px;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.pay-choice:hover { border-color: var(--line-strong); }
.pay-choice.selected { border-color: var(--green); background: var(--green-soft); }
.pay-choice input { position: absolute; opacity: 0; pointer-events: none; }
.pay-choice label {
  display: block;
  position: relative;
  cursor: pointer;
  padding: 12px 14px 12px 42px;
}
/* Rádio desenhado à mão: anel fino + ponto centrado na linha do título.
   (O anterior era um aro de 6px num círculo de 18px: parecia um spinner e
   com o selo a quebrar linha desalinhava.) */
.pay-choice label:before {
  content: "";
  position: absolute;
  left: 14px; top: 16px;
  width: 16px; height: 16px;
  border-radius: 50%;
  border: 1.5px solid #b9bec6;
  background: #fff;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.pay-choice input:checked + label:before {
  border-color: var(--green);
  background: var(--green);
  box-shadow: inset 0 0 0 3px var(--card);
}
.pay-choice input:focus-visible + label {
  outline: 2px solid var(--green);
  outline-offset: 2px;
  border-radius: 12px;
}
.pay-choice-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pay-choice-head em { font-style: normal; }
.pay-choice-body { display: block; margin-top: 4px; font-size: 13px; color: var(--muted); }
.pay-choice-body strong { white-space: nowrap; }
.badge-recommended { background: var(--green-soft); color: var(--green-dark); font-size: 11px; padding: 2px 8px; border-radius: 20px; font-weight: 600; }
.badge-new { background: #eef0f3; color: var(--ink-700); font-size: 11px; padding: 2px 8px; border-radius: 20px; font-weight: 600; }

/* ---------- Pedido: pagamento cripto ---------- */
.btn-nowpayments { background: #662d91; color: #fff; }
.btn-nowpayments:hover { background: #552577; color: #fff; }
.np-card { text-align: center; }
.np-card .muted { text-align: left; }
.np-wait { margin: 14px 0 0; color: var(--muted); font-size: 13.5px; }
.dots span { animation: npblink 1.2s infinite; }
.dots span:nth-child(2) { animation-delay: 0.2s; }
.dots span:nth-child(3) { animation-delay: 0.4s; }
@keyframes npblink { 0%, 60%, 100% { opacity: 0.25; } 30% { opacity: 1; } }

/* ---------- Admin de templates ---------- */
.admin-actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.admin-table { width: 100%; }
.admin-table td > small { font-size: 12px; }
/* As ações ficam em linha pelo `inline-block`, NÃO por `display: flex`: um `<td>` que
   deixa de ser `table-cell` não estica até à altura da linha (medido: 54px numa linha
   de 80px) e o `border-bottom` dele ficava 26px acima do das outras células — lê-se
   como «a linha debaixo partida». */
.td-actions { white-space: nowrap; text-align: right; }
.td-actions > * { vertical-align: middle; }
.td-actions form { display: inline-block; margin: 0 0 0 8px; }
.badge-gold { background: var(--gold-soft); color: var(--gold-dark); }
.badge-green { background: var(--green-soft); color: var(--green-dark); }
.badge-red { background: #fdecea; color: #b3261e; }
/* A pastilha neutra: para o que é facto e não avaliação (o tipo de documento,
   o dispositivo). As de estado — verde/dourado/vermelho — continuam a dizer se a
   pessoa chegou ou não ao fim. */
.badge-soft { background: var(--paper-soft); color: var(--muted); }
.btn-danger-ghost { background: transparent; color: var(--red); border: 1.5px solid #f1c4be; }
.btn-danger-ghost:hover { background: #fdecea; }
.btn-icon-danger { color: var(--red); }
.btn-icon-danger:hover { background: #fdecea; border-color: #f1c4be; color: #b3261e; }
.btn-icon-green { color: var(--green-dark); background: var(--green-soft); border-color: #cfe7dc; }
.btn-icon-green:hover { background: var(--green); border-color: var(--green); color: #fff; }
.btn-icon-cancel { color: var(--muted); }
.btn-icon-cancel:hover { background: #f6f3ee; border-color: var(--line); color: var(--ink-700); }
.chk-row { display: flex; gap: 24px; flex-wrap: wrap; margin-top: 8px; font-size: 14px; }
.chk-row input { margin-right: 6px; }
.admin-form .card { margin-bottom: 16px; }
.admin-form .card h2 { margin-bottom: 16px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0 16px; }
@media (max-width: 680px) { .grid-3 { grid-template-columns: 1fr; } }
.color-grid { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); }
.color-grid input[type="color"] { width: 100%; height: 42px; padding: 4px; }
.sec-row {
  display: grid;
  grid-template-columns: 210px 1fr 74px;
  gap: 12px;
  align-items: center;
  padding: 8px 0;
  border-bottom: 1px dashed var(--line);
}
.sec-row:last-child { border-bottom: 0; }
.sec-visible { display: flex; gap: 8px; align-items: center; font-size: 14px; }
.sec-label-wrap { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.ats-note { color: var(--muted); font-size: 12px; }
.ats-note.warn { color: #9a6a00; font-weight: 600; }
.sec-label { padding: 8px 10px; border: 1.5px solid var(--line); border-radius: var(--radius-sm); font-size: 14px; font-family: inherit; }
.sec-order { width: 64px; padding: 8px 10px; border: 1.5px solid var(--line); border-radius: var(--radius-sm); }
@media (max-width: 680px) { .sec-row { grid-template-columns: 1fr; } }

/* ---------- Footer ---------- */
.back-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.2px;
  color: var(--muted);
  text-decoration: none;
  margin-bottom: 10px;
  transition: color 0.15s ease;
}
.back-link:hover { color: var(--green); }
/* Na página do PEDIDO o back-link é o único caminho de volta (a navbar não
   tem «Os meus documentos») e é onde o cliente aterra depois de pagar —
   13px cinzentos no topo eram um link de rodapé a fazer de navegação
   principal. Aqui vira botão outline, do tamanho dos outros. */
.order-wrap .back-link {
  font-size: 14px;
  color: var(--ink-900);
  padding: 9px 16px;
  border-radius: var(--radius-sm);
  box-shadow: inset 0 0 0 1.5px var(--line);
  margin-bottom: 18px;
}
.order-wrap .back-link:hover {
  color: var(--green);
  box-shadow: inset 0 0 0 1.5px var(--green);
}
/* O ícone do «Painel de documentos» tem de ter tamanho: um SVG sem largura própria
   estica até ao tamanho do browser. 16px é a altura do texto do link. */
.order-wrap .back-link .ico { width: 16px; height: 16px; flex: none; }

/* ---------- Footer ---------- */
.site-footer { border-top: 1px solid var(--line); padding: 34px 0 26px; color: var(--muted); font-size: 13.5px; }
.site-footer p { margin: 0; }
.site-footer .trust-strip {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px 34px;
  margin: 0 0 26px;
  padding-bottom: 20px;
  border-bottom: 1px dashed var(--line);
}
.site-footer .trust-item { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600; color: var(--muted); }
/* Ícones a traço, iguais aos do resto do rodapé (em vez de emoji). */
.site-footer .trust-ico { display: inline-flex; flex: none; width: 16px; height: 16px; }
.site-footer .trust-ico svg { width: 100%; height: 100%; display: block; }
/* Grelha elástica: se uma coluna desaparecer (ex.: redes sociais desligadas),
   as restantes esticam em vez de deixar um buraco. O mínimo das colunas é
   baixo de propósito — o conteúdo (links, redes) parte em várias linhas. */
.foot-grid {
  display: grid;
  grid-template-columns: minmax(180px, 1.4fr) repeat(auto-fit, minmax(124px, 1fr));
  gap: 26px 28px;
}
.foot-title {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -0.4px;
  color: var(--ink-950);
  margin: 0 0 14px;
}
/* Identificação legal (quando preenchida em /gestao_interna/parametros/).
   Especificidade acima de `.site-footer p { margin: 0 }`. */
.site-footer .foot-legal {
  margin: 6px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--muted);
}
.foot-col h2 {
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--ink-900);
  margin: 0 0 12px;
}
.foot-col a { display: block; color: var(--muted); text-decoration: none; margin-bottom: 9px; }
.foot-col a:hover { color: var(--text); text-decoration: underline; }
.foot-col a:focus-visible,
.foot-social a:focus-visible,
.foot-title:focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 2px;
  border-radius: 4px;
}
.foot-col .foot-line {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 9px;
  color: var(--muted);
}
.foot-col a.foot-line { text-decoration: none; }
.foot-col a.foot-line:hover { color: var(--text); }
.foot-col .foot-line svg { width: 15px; height: 15px; flex: none; }
/* Uma rede por linha, como as restantes colunas do rodapé: em linha horizontal
   o conjunto (~248px) não cabia na coluna e o LinkedIn saía fora da grelha. */
.foot-social { display: flex; flex-direction: column; gap: 9px; }
.foot-social a { display: inline-flex; align-items: center; gap: 6px; margin-bottom: 0; color: var(--muted); }
.foot-social svg { width: 16px; height: 16px; }
.foot-note {
  margin: 26px 0 0 !important;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  font-size: 12px;
  /* --muted-light dava ~2.9:1 sobre o fundo (falhava AA); --muted dá ~5.2:1. */
  color: var(--muted);
  text-align: center;
}
@media (max-width: 760px) {
  .foot-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 460px) {
  .foot-grid { grid-template-columns: 1fr; gap: 22px; }
}
.legal { max-width: 780px; margin: 0 auto; padding: 30px 0 40px; }
.legal .legal-title { font-size: 32px; font-family: var(--font-display); letter-spacing: -0.6px; margin: 0 0 18px; }
.legal-body p, .legal-body li { font-size: 15px; line-height: 1.65; color: var(--ink-700); }
.legal-body h2 { font-size: 19px; margin: 26px 0 10px; letter-spacing: -0.2px; }
.legal-body ul { margin: 8px 0 16px; padding-left: 22px; }
.legal-body a { text-decoration: underline; text-underline-offset: 3px; }
.legal-body code { font-family: var(--font-mono); font-size: 13px; background: var(--line); padding: 1px 5px; border-radius: 5px; }
.legal-contact { margin-top: 22px; font-weight: 600; }

/* ---------- Landing (`/`) ---------- */
/* O hero é só texto, e CENTRADO: a promessa e o botão. A fila de miniaturas que
   aqui esteve passou para a secção MODELOS, que é onde se escolhe e se navega —
   tê-las nas duas era ver os mesmos PDFs duas vezes antes de chegar ao botão.
   Sem a segunda coluna, o h1 fica com a largura toda, e centrado lê-se como o
   fecho de uma frase só em vez do arranque de uma coluna. */
/* Duas colunas: a promessa à esquerda, o PDF à direita. Antes era só texto
   centrado — limpo, mas a página mostrava o produto a 1400 px de scroll. */
.lp-hero {
  display: grid;
  grid-template-columns: 1.02fr 0.98fr;
  gap: 56px;
  align-items: center;
  max-width: 1060px;
  margin: 0 auto;
  padding: 64px 0 52px;
  text-align: left;
}
.lp-hero-text { max-width: 540px; }
/* Três folhas em leque, a Moderno à frente. A inclinação é de propósito e é
   grande (8°): a 1,6° lia-se como descuido, não como papel pousado. O leque é o
   que diz «há modelos para escolher» sem uma frase; a folha da frente é a que
   se lê. Toda a pilha é um link para os modelos. */
.lp-hero-shot {
  margin: 0;
  position: relative;
  display: block;
  width: 100%;
  max-width: 400px;
  /* 64px de folga à direita: as folhas de trás rodam e saem 60px para fora da
     folha da frente. Sem esta margem, o leque era cortado pela borda da página
     (visto a 1280px) — o `justify-self: end` encostava tudo ao limite. */
  margin-right: 64px;
  justify-self: end;
  color: inherit;
  text-decoration: none;
  isolation: isolate;
}
.lp-sheet {
  display: block;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid var(--line);
  background: #fff;
  box-shadow: 0 34px 60px -34px rgba(12, 30, 22, 0.45), 0 2px 6px rgba(12, 30, 22, 0.06);
}
.lp-sheet img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top;
}
.lp-sheet-front {
  position: relative;
  z-index: 3;
  aspect-ratio: 210 / 297;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
/* As duas de trás: a mesma altura, mais estreitas e inclinadas para fora. A
   sombra é mais baixa do que a da frente — assim leem-se como o segundo e o
   terceiro modelo, não como três produtos. */
.lp-sheet-lado {
  position: absolute;
  inset: -5% 0 0;
  aspect-ratio: 210 / 297;
  box-shadow: 0 18px 34px -26px rgba(12, 30, 22, 0.4);
}
.lp-sheet-esq {
  z-index: 1;
  transform: translate(-15%, -6%) rotate(-8deg) scale(0.92);
  transform-origin: 100% 40%;
}
.lp-sheet-dir {
  z-index: 2;
  transform: translate(15%, -5%) rotate(8deg) scale(0.92);
  transform-origin: 0% 40%;
}
/* As três etiquetas: dizem o que o leque não consegue dizer sozinho — que o
   modelo foi escolhido, que sai PDF e que não é preciso Word. São brancas e
   flutuam fora da folha, para se lerem como anotações e não como parte do CV. */
.lp-chip {
  position: absolute;
  z-index: 4;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border-radius: 999px;
  background: #fff;
  border: 1px solid var(--line);
  box-shadow: 0 10px 24px -14px rgba(12, 30, 22, 0.45);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  letter-spacing: -0.01em;
}
.lp-chip::before {
  content: "";
  width: 6px; height: 6px; border-radius: 999px;
  background: var(--green);
}
/* A fotografia do CV está no canto superior ESQUERDO — por isso a primeira
   etiqueta vai para a direita. Em triângulo: canto de cima, meio da esquerda,
   canto de baixo. Nenhuma passa por cima do rosto. */
.lp-chip-1 { top: 3%; right: -9%; }
.lp-chip-2 { top: 40%; left: -11%; }
.lp-chip-3 { bottom: 7%; right: -11%; }
.lp-hero-shot:hover .lp-sheet-front,
.lp-hero-shot:focus-visible .lp-sheet-front {
  transform: translateY(-3px);
  box-shadow: 0 40px 70px -34px rgba(12, 30, 22, 0.5), 0 2px 6px rgba(12, 30, 22, 0.06);
}
/* O cabeçalho é pegajoso e comia o título da secção ao saltar para #modelos. */
#modelos, #como, #recebes, #mostra { scroll-margin-top: 92px; }
.lp-hero-shot:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 6px;
  border-radius: 10px;
}
/* O h1 do hero não leva `<br>`: o texto é longo demais para a coluna e um
   `<br>` fixo só empurrava a quebra para o pior sítio («carta de» ficava
   sozinho numa linha). O `balance` reparte as linhas em vez de as amontoar. */
.lp-hero .display { margin: 0 0 20px; text-wrap: balance; }
.lp-hero .lp-sub { margin: 0 0 26px; }
.lp-hero .lp-cta { justify-content: flex-start; }
.lp-sub { margin: 0 auto 26px; max-width: 480px; color: var(--muted); font-size: 17px; line-height: 1.6; }
/* `center` e não `flex-start`: com o hero centrado, um botão encostado à
   esquerda lia-se como se o texto estivesse à esquerda. Vale para as três
   variantes do hero (`?f=cv`, `?f=carta` e a neutra), que usam a mesma regra. */
.lp-cta { display: flex; align-items: center; justify-content: center; gap: 12px; flex-wrap: wrap; }
/* O alívio de risco junto ao botão: quem está com o rato no «Começar» lê isto antes
   de clicar, sem ter de chegar ao FAQ. */

/* O carrossel de modelos: o track é um scroll horizontal com snap (o mesmo
   padrão da faixa de estilos do editor); as setas fazem scroll por um cartão e
   escondem-se quando não há onde rolar (o JS põe `hidden`). */
.lp-carousel {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 10px;
}
.lp-carousel-track {
  /* Sem isto o track (grid item) não encolhe abaixo do conteúdo e empurra a
     seta da direita para fora do ecrã — as setas existiam e não se viam. */
  min-width: 0;
  display: flex;
  gap: 18px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-left: 4px;
  padding: 6px 4px 14px;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
}
.lp-carousel-track::-webkit-scrollbar { display: none; }
.lp-carousel-track .style-card {
  flex: 0 0 auto;
  width: clamp(170px, 19vw, 210px);
  scroll-snap-align: start;
}
.lp-carousel-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 999px;
  border: 1.5px solid var(--line);
  background: var(--card);
  color: var(--ink-700);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.lp-carousel-btn:hover { border-color: var(--green); color: var(--green-dark); }
.lp-carousel-btn svg { width: 20px; height: 20px; }
.lp-carousel-btn[hidden] { display: none; }

/* Uma secção = um recado. Cada uma abre com `lp-intro` (kicker + título), e o corpo que
   segue é a secção em si. O tónus é de lista editorial assente no papel — nada de
   caixas verdes por todo o lado, que era o ar de «gerado por IA». */
.lp-sec { padding: 66px 0 0; }

/* O exemplo do CV: duas colunas, texto à esquerda e a tiragem real à direita.
   Em telemóvel a imagem passa para baixo do texto, e a lista alinha à esquerda. */
.lp-mostra { display: grid; grid-template-columns: 1fr 1fr; gap: 56px; align-items: center; }
.lp-mostra-txt { max-width: 460px; }
.lp-lista { list-style: none; margin: 18px 0 26px; padding: 0; display: grid; gap: 10px; }
.lp-lista li { position: relative; padding-left: 26px; font-size: 14.5px; line-height: 1.5; color: var(--ink-800, #2b2b2b); }
.lp-lista li::before { content: ""; position: absolute; left: 0; top: 3px; width: 16px; height: 16px; border-radius: 50%; background: var(--green, #0e8a5e); opacity: .12; }
.lp-lista li::after { content: "✓"; position: absolute; left: 3px; top: 0; font-size: 11px; line-height: 18px; color: var(--green-dark, #0b6b4a); }
.lp-mostra-img { margin: 0; }
.lp-mostra-img img { display: block; width: 100%; height: auto; border: 1px solid var(--line); border-radius: 12px; box-shadow: 0 18px 40px rgba(12, 20, 16, .10); background: var(--paper, #fff); }
@media (max-width: 760px) {
  .lp-mostra { grid-template-columns: 1fr; gap: 28px; }
  .lp-mostra-txt { max-width: none; }
}
.lp-intro { max-width: 660px; margin-bottom: 24px; }
.lp-kicker { font-family: var(--font-display); font-size: 12px; font-weight: 700; letter-spacing: 1.2px; text-transform: uppercase; color: var(--green-dark); margin: 0 0 8px; }
.lp-h2 { font-family: var(--font-display); font-size: clamp(22px, 2.6vw, 30px); letter-spacing: -0.5px; margin: 0; line-height: 1.15; }

/* O porquê: em vez de cartões, uma grelha fechada por riscos finos (o material do
   papel). Funciona para 1, 2 ou 3 colunas: o traço de cima e o da esquerda pertencem
   à grelha, e cada célula contribui com o de baixo e o da direita. */
.lp-feats { display: grid; grid-template-columns: repeat(3, 1fr); list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); border-left: 1px solid var(--line); }
.lp-feats li { padding: 26px 24px 30px; border-bottom: 1px solid var(--line); border-right: 1px solid var(--line); }
.lp-ico { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; color: var(--green-dark); }
.lp-ico svg { width: 24px; height: 24px; }
.lp-feats h3, .lp-steps h3 { margin: 8px 0 6px; font-size: 16.5px; letter-spacing: -0.2px; color: var(--ink-950); }
.lp-feats p, .lp-steps p { margin: 0; font-size: 14px; line-height: 1.6; color: var(--muted); }

/* A mostra de estilos na landing é uma grelha PARADA (sem carrossel nem setas): aqui
   só se vende, a escolha acontece no editor. O `.style-card` nasce com largura fixa e
   `flex`, que não interessam dentro de uma grelha — `width: auto` entrega as colunas
   à grelha. */
.lp-estilos { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 18px; }
.lp-estilos .style-card { width: auto; }

/* Os dois produtos, lado a lado. É a mesma grelha dos estilos com dois cartões em
   vez de quatro: o que muda é a tiragem — o CV mostra o PDF real, a carta mostra
   a página desenhada em CSS (não há PNG da carta, e não se inventa uma imagem
   que não corresponde a nada). O preço de cada um fica dentro do cartão, porque
   a pergunta ao ver «CV» e «Carta» lado a lado é sempre «qual é mais barato». */
.lp-produtos-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 20px;
}
.lp-produtos .prod-card {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  transition: border-color 0.15s, transform 0.15s;
}
.lp-produtos .prod-card:hover { border-color: var(--line-strong); transform: translateY(-2px); }
.lp-produtos .prod-card:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }
.lp-produtos .prod-shot {
  display: block;
  background: var(--paper-soft);
  border-bottom: 1px solid var(--line);
}
.lp-produtos .prod-shot .tpl-thumb {
  display: block;
  width: 100%;
  aspect-ratio: 210 / 297;
  object-fit: cover;
  object-position: top;
}
/* Mesma anatomia da tiragem do cartão na galeria, à escala da landing. */
/* (O mock `.prod-shot-letter` saiu: a carta mostra a miniatura real do PDF,
   `carta-moderno.png` — a mesma imagem da faixa de modelos do editor.) */
.lp-produtos .prod-meta {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 16px 18px 20px;
}
.lp-produtos .prod-meta b { font-size: 16px; color: var(--ink-950); letter-spacing: -0.2px; }
.lp-produtos .prod-meta small { font-size: 12.5px; color: var(--muted); }
.lp-produtos .prod-price {
  font-weight: 700;
  color: var(--green-dark) !important;
  margin-top: 4px;
}
.lp-produtos .prod-card:hover .prod-meta b { text-decoration: underline; text-underline-offset: 2px; }

/* Os passos, no registo simples: número + título + uma linha, com um traço fino a
   dar a ordem. Sem caixas — basta o número verde a marcar o lugar. */
.lp-steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; list-style: none; margin: 0; padding: 0; }
.lp-steps li { border-top: 2px solid var(--line-strong); padding-top: 16px; }
.lp-num { display: block; font-family: var(--font-display); font-size: 14px; font-weight: 800; letter-spacing: 1px; color: var(--green-dark); }

/* O preço é para se ler de longe: é a única secção de um número só. */
.lp-preco { text-align: center; }
.lp-preco .lp-kicker, .lp-preco .lp-h2 { display: block; max-width: 520px; margin-left: auto; margin-right: auto; }
.lp-preco .lp-h2 { margin-bottom: 20px; }
.lp-valor { margin: 0; font-family: var(--font-display); font-weight: 800; font-size: clamp(34px, 5vw, 46px); letter-spacing: -1px; color: var(--ink-950); line-height: 1; }
.lp-desde { font-size: 0.55em; font-weight: 700; letter-spacing: -0.5px; color: var(--muted); }
.lp-preco-note { margin: 16px auto 0; max-width: 420px; color: var(--muted); font-size: 14px; }
/* Confiança junto do preço: factos simples, o link de devolução é o único clicável. */
.lp-trust { display: flex; justify-content: center; gap: 10px; flex-wrap: wrap; list-style: none; margin: 18px 0 0; padding: 0; }
.lp-trust li { font-size: 13.5px; color: var(--ink-700); background: var(--paper-soft); border: 1px solid var(--line); border-radius: 999px; padding: 5px 14px; }
.lp-trust a { color: var(--green-dark); font-weight: 700; text-decoration: none; }
.lp-trust a:hover { text-decoration: underline; }

/* Os preços dos DOIS produtos, lado a lado: a pergunta «qual é mais barato»
   responde-se à vista. Cada cartão leva o número grande e o que inclui. */
.lp-precos-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 380px));
  gap: 20px;
  justify-content: center;
  justify-content: center;
}
/* Um cartão só (cartas suspensas): a grelha de dois deixava metade da página
   vazia à direita. Com `is-unico` o cartão fica ao centro, com a mesma largura. */
.lp-precos-grid.is-unico { grid-template-columns: minmax(0, 380px); }

.lp-preco-card {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 26px 26px 22px;
}
.lp-preco-card h3 {
  margin: 0 0 10px;
  font-family: var(--font-display);
  font-size: 16px;
  letter-spacing: -0.2px;
  color: var(--ink-950);
}
.lp-preco-card .lp-valor { margin: 0 0 14px; }
.lp-preco-lista {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.lp-preco-lista li {
  font-size: 14px;
  color: var(--muted);
  padding-left: 20px;
  position: relative;
}
.lp-preco-lista li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 7px;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--green);
}

.lp-mais { margin: 14px 0 0; }
.lp-mais a { color: var(--green-dark); font-weight: 700; text-decoration: none; }
.lp-mais a:hover { text-decoration: underline; }
/* CTA de fecho da landing: a última secção não é para ficar suspensa — fecha com o
   mesmo botão que abre o produto. */
.lp-final { margin-top: 36px; display: flex; justify-content: center; }

@media (max-width: 900px) {
  /* Em ecrã estreito o hero desce um bocado e aperta a coluna. O `text-align` e o
     `justify-content` já vêm de cima — o hero é centrado em todas as larguras. */
  .lp-hero {
    grid-template-columns: 1fr;
    gap: 34px;
    padding-top: 26px;
    text-align: center;
  }
  .lp-hero-text { max-width: 560px; margin: 0 auto; }
  .lp-hero .lp-cta { justify-content: center; }
  .lp-hero .lp-sub { margin-left: auto; margin-right: auto; }
  /* A tiragem continua, mas pequena e direita: é a prova, não o assunto. */
  .lp-hero-shot { max-width: 300px; margin: 0 auto; }
  .lp-sheet-back { transform: translate(-16px, -40px) scale(0.94); }
  .lp-sub, .lp-cta { margin-left: auto; margin-right: auto; }
  .lp-precos-grid { grid-template-columns: 1fr; }
}

@media (max-width: 860px) {
  .lp-feats { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .lp-feats { grid-template-columns: 1fr; }
  .lp-steps { grid-template-columns: 1fr; gap: 22px; }
}

/* ---------- Painel de controlo (`/home/`) ---------- */
/* É o mapa do que o produto oferece, não a galeria: o cabeçalho dá o contexto e os
   recentes usam a MESMA grelha e os MESMOS cartões da galeria (`.cvs-grid`/`.cv-card`),
   com o «Criar novo CV» como primeira célula. Sem cartões, o vazio convida a criar. */
.dash-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  /* Abre a 26px, como todas as cabeças da área. Eram 36px — a galeria era a única
     página que começava mais abaixo, e ele vê a diferença a saltar de página. */
  padding: 26px 2px 6px;
}
/* O título ENCOLHE para o filtro caber ao lado. Sem isto, `flex-wrap: wrap` media
   o título inteiro: «As tuas Cartas de apresentação» (590px) passava dos 500px de
   viewport e atirava o funil para uma segunda linha, enquanto «Os teus CVs» (243px)
   cabia — as duas galerias ficavam com cabeçalhos de alturas diferentes.

   O `flex-basis: 0` (e não `auto`) é o que resolve: o `flex-wrap` decide a quebra
   de linha pela tamanho TEÓRICO de cada item, e `auto` valia a largura do texto
   inteiro — o título «media» a linha e o funil era atirado para baixo antes de
   haver qualquer encolhimento. Com base 0 o título parte logo de 0 e cresce só
   com o espaço que sobra, os dois ficam sempre na mesma linha e é o TEXTO do
   título que quebra. O `min-width: 0` autoriza o encolhimento (o padrão `auto`
   trava a caixa no mínimo do conteúdo). */
.dash-head-txt { flex: 1 1 0; min-width: 0; }
/* `overflow-wrap: anywhere` para o título não transbordar a caixa encolhida quando o
   texto não tem espaço natural (ou é um nome de ficheiro colado). */
/* A linha é a mesma das outras cabeças (1.08) e a margem é zero: a folga até ao que vem abaixo é do bloco, não do título. A contagem («12») vive DENTRO do `h1`, por isso estes 6px não separavam nada. */
.dash-title { margin: 0; color: var(--ink-950); line-height: 1.08; overflow-wrap: anywhere; }
.dash-sub { margin: 0; color: var(--muted); font-size: 15.5px; }
/* O filtro nunca encolhe nem parte: `flex: 0 0 auto` diz ao `flex-wrap` que esta
   caixa é intocável, e o `margin-left: auto` encosta-a à direita na mesma linha.

   O `align-items: flex-start` do `.dash-head` é o que resolve «o ícone não pode
   subir mais»: com `flex-end` o funil alinhava com a BASE do título, e o título
   das cartas ocupa DUAS linhas em telemóvel — o funil descia uma linha inteira e
   ficava a meio do ecrã, sem relação com o texto ao lado. Alinhado ao topo, fica à
   altura da PRIMEIRA linha do título, quer o título tenha uma quer duas. E com o
   título de uma linha (os CVs) topo e base coincidem, portanto o funil fica
   exatamente onde estava. */
.dash-head-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 auto;
  margin-left: auto;
}
.dash-head-actions .btn svg { width: 16px; height: 16px; }
@media (max-width: 640px) {
  .dash-head { gap: 14px; padding-bottom: 4px; }
}

/* `min-width: 0` na secção: sem isto o item da grelha fica com `min-width: auto` e
   a pista nunca encolhe abaixo do min-content da linha (ver `minmax(0, 1fr)` abaixo). */
.dash-sec { margin-top: 8px; min-width: 0; }
/* As duas secções do painel lado a lado: CV à esquerda, carta à direita. Em ecrã
   estreito caem para uma coluna (a ordem de leitura mantém-se: CV, depois carta).

   ⚠️ `minmax(0, 1fr)`, nunca `1fr`: `1fr` é `minmax(auto, 1fr)` e o `auto` é o
   min-content do item. A linha do documento tem min-content ~358px (miniatura 38px
   + seta 18px + o `tempo_editado`, que é `nowrap`), portanto a pista ficava
   prisoner a 358px e a GRELHA transbordava o `.container`: aos 333px de viewport as
   secções acabavam em 379.5 (46.5px fora). Como `html, body` têm
   `overflow-x: clip` (ver o topo), o transbordo não dá barra — desaparece, e o que
   se via era o conteúdo cortado à direita, para lá do botão do hambúrguer. Com `minmax(0, …)`
   a pista encolhe e é o `.doc-row-time` (que tem `text-overflow: ellipsis`) que corta
   o texto — que é o que se quer. */
.dash-cols {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 0 28px;
  align-items: start;
}
@media (max-width: 900px) {
  .dash-cols { grid-template-columns: minmax(0, 1fr); gap: 0; }
}

/*** Linhas compactas do painel (.doc-row) ***/
/* O tamanho que os sites do género usam (Google Docs, Canva): miniatura pequena à
   esquerda + nome/estado à direita, ~64px de altura. A tiragem A4 grande é da
   GALERIA, onde se folheia; o painel é um mapa — o que se quer ver de relance é
   o que existe e o que falta, e os dois produtos cabem lado a lado. */
.doc-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 14px;
}
/* O contentor de cada linha: embrulha a linha e o menu «⋯» como irmãos — um
   `<form>` dentro do `<a>` da linha partia o HTML e o menu caía para fora. O
   menu é posicionado sobre a linha (canto direito). */
.doc-item { position: relative; }
.doc-row-menu {
  position: absolute;
  top: 50%;
  right: 10px;
  transform: translateY(-50%);
}
.doc-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px;
  border-radius: 12px;
  background: var(--card);
  border: 1.5px solid var(--line);
  text-decoration: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.doc-row:hover { border-color: var(--green); box-shadow: 0 10px 22px -18px rgba(13, 20, 32, 0.45); }
.doc-row-thumb {
  flex: 0 0 44px;
  width: 44px;
  height: 60px; /* proporção A4 em miniatura: 44 × 297/210 ≈ 62 */
  border-radius: 5px;
  overflow: hidden;
  background: var(--paper-soft);
  border: 1px solid var(--line);
}
.doc-row-thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top;
  background: #fff;
}
.doc-row-empty { display: block; width: 100%; height: 100%; background: var(--line); }
.doc-row-main {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  flex: 1 1 auto;
}
.doc-row-name {
  font-weight: 700;
  font-size: 14px;
  color: var(--ink-900);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.doc-row-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  font-size: 12px;
  color: var(--muted);
}
.doc-row-time { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* A pastilha de estado: a mesma cor do badge da galeria, em miniatura. */
.doc-row-state {
  flex: 0 0 auto;
  font-size: 11px;
  font-weight: 700;
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--paper-soft);
  color: var(--muted);
}
.doc-row-state--paid { background: #e7f3ee; color: var(--green-dark); }
.doc-row-state--pending { background: #fdf3d7; color: #8a6d1a; }
.doc-row-state--expired { background: #fde8e8; color: #a03030; }
.doc-row-state--archived { background: #eef0f3; color: var(--muted); }
.doc-row-go {
  flex: 0 0 auto;
  margin-left: auto;
  color: var(--muted);
  opacity: 0;
  transition: opacity 0.15s ease;
}
.doc-row:hover .doc-row-go, .doc-row:focus-visible .doc-row-go { opacity: 1; }
.doc-row-go svg { width: 18px; height: 18px; display: block; }
/* A cria: tracejada, do tamanho das outras — a ideia «podes criar um dos dois»
   lê-se na primeira linha de cada coluna. */
.doc-row-new {
  background: transparent;
  border-style: dashed;
  border-color: var(--line-strong);
  box-shadow: none;
}
.doc-row-new:hover { box-shadow: none; }
.doc-row-empty--new {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--paper-soft);
  color: var(--green-dark);
}
.doc-row-empty--new svg { width: 20px; height: 20px; }
/* No telemóvel a linha compacta já é o tamanho certo: só aperta o gap. */
@media (max-width: 560px) {
  .doc-list { gap: 8px; }
  .doc-row { padding: 7px; gap: 10px; }
  .doc-row-thumb { flex-basis: 38px; height: 52px; }
}
.dash-sec-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 0 4px 2px;
}
.dash-sec-head h1, .dash-sec-head h2 { font-family: var(--font-display); font-size: 18px; letter-spacing: -0.3px; margin: 0; }
.dash-all { color: var(--green-dark); font-weight: 700; text-decoration: none; font-size: 14px; }
.dash-all:hover { text-decoration: underline; }

/* A cria: fundo transparente para se ler como «o próximo», não como mais um CV. */
.cv-card-new .cv-shot-new { background: transparent; }
.cv-shot-new {
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1.5px dashed var(--line-strong);
  border-radius: 6px;
  color: var(--green-dark);
  background: var(--paper-soft);
}
.cv-shot-new svg { width: 34px; height: 34px; }

.dash-empty { margin-top: 8px; }
.dash-empty h2 { font-size: 20px; }
.dash-empty p { color: var(--muted); margin: 0 0 16px; }

/* Perguntas frequentes: o MESMO bloco na página de info e na landing (os itens vivem em
   `partials/faq_items.html`). */
.faq details { border: 1px solid var(--line); border-radius: 12px; padding: 14px 18px; margin-bottom: 10px; background: var(--card); box-shadow: var(--shadow); }
.faq summary { font-weight: 700; cursor: pointer; color: var(--ink-900); }
.faq details p { margin: 10px 0 0; font-size: 15px; line-height: 1.6; color: var(--ink-700); }

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
  .hero-inner { grid-template-columns: 1fr; gap: 8px; }
}
@media (max-width: 700px) {
  .steps { gap: 4px; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
}
/* Foto do CV */
.cropper-wrap { margin-top: 14px; }
.cropper-wrap canvas {
  display: block; width: 100%; max-width: 260px; max-height: 260px;
  border: 1.5px solid var(--line); border-radius: 12px; cursor: grab;
  background: repeating-conic-gradient(#eef1f4 0 25%, #fff 0 50%) 50% / 20px 20px;
  touch-action: none;
}
.cropper-wrap canvas:active { cursor: grabbing; }
.cropper-controls { display: flex; flex-wrap: wrap; gap: 16px; margin: 12px 0; align-items: center; }
.cropper-controls label { display: flex; flex-direction: column; gap: 6px; font-size: 13px; color: var(--muted); }
.cropper-zoom input[type="range"] { width: 160px; }
.photo-preview {
  width: 120px; height: 120px; object-fit: cover; border-radius: 50%;
  border: 2px solid var(--line); display: block; margin: 0;
}
#photo-current { margin-top: 10px; }
#photo-status { margin-left: 10px; }

.photo-pick {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 18px; margin-top: 10px;
  border: 1.5px dashed var(--line-strong); border-radius: 12px;
  background: var(--paper-soft); color: var(--ink-700);
  font-weight: 600; font-size: 14px; cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
  user-select: none;
}
.photo-pick svg { width: 18px; height: 18px; }
.photo-pick:hover, .photo-pick:focus-visible { border-color: var(--green); background: var(--green-soft); }
.photo-pick.drag { border-color: var(--green); background: var(--green-soft); color: var(--green-dark); }

.photo-thumb { position: relative; display: inline-block; }
.photo-x {
  position: absolute; top: -6px; right: -6px;
  width: 24px; height: 24px; border-radius: 50%;
  border: 2px solid var(--card); background: var(--ink-950); color: #fff;
  font-size: 14px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 2px 6px rgba(13, 20, 32, 0.35);
  transition: transform 0.12s ease, background 0.12s ease;
}
.photo-x:hover { transform: scale(1.12); background: var(--red); }

/* A foto e uma COLUNA de «Dados pessoais», como no formulario que ele mostrou
   (cvwizard): o rotulo «Foto» por cima de um quadrado claro com a camara, e os
   campos ao lado. Sem caixa propria e sem texto de instrucoes.
   Vazio, o proprio quadrado e o botao (tracejado, com a camara). Com foto, a foto
   enche o quadrado, o quadrado inteiro passa a ser o botao (tocar = trocar) e a
   cruz de remover fica no canto. As medidas antigas (avatar redondo de 120px,
   pilula com legenda) ficam para o perfil da conta, que usa as mesmas classes. */
.dados-grid { display: grid; grid-template-columns: minmax(0, 150px) repeat(2, minmax(0, 1fr)); gap: 12px 24px; align-items: start; }
/* O aviso das definições e o resumo ocupam a largura toda: a primeira linha da
   grelha é [Foto][campo][campo], como no formulário dele. */
/* O nome ocupa sozinho as duas colunas dos campos; o título profissional e a área
   profissional ficam lado a lado na linha seguinte, à direita da foto. É a caixa da
   foto (span 2) que tem a altura das duas linhas. */
.dados-grid > .campo-largo { grid-column: 2 / -1; }
.dados-grid > .largo { grid-column: 1 / -1; }
/* Sem foto (os modelos que não a mostram) a coluna de 200px ficava vazia e o nome
   preso lá dentro: sobram as duas colunas dos campos. O guião troca a classe quando
   o estilo muda sem recarregar a página. */
.dados-grid.sem-foto { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.dados-grid.sem-foto > .campo-largo { grid-column: auto; }
/* Telemóvel: uma coluna. O `grid-column: 2 / -1` cria uma coluna implícita numa
   grelha de uma coluna, e as consultas de media não somam especificidade — a versão
   sem foto (`.dados-grid.sem-foto`) ganharia a esta linha. */
@media (max-width: 640px) {
  .dados-grid, .dados-grid.sem-foto { grid-template-columns: minmax(0, 1fr); gap: 14px; }
  .dados-grid > .campo-largo, .dados-grid.sem-foto > .campo-largo { grid-column: auto; }
  #photo-card { grid-row: auto; align-self: start; }
}

/* ---------- As Definições da conta (`/contas/perfil/`) ----------
   A cabeça do cartão: a foto à esquerda e, ao lado dela, quem é a pessoa (o nome e a forma como
   entra). A foto deixa de ser uma coluna da grelha dos campos — era para lá que a data de
   nascimento caía, sozinha, quando os compridos passaram à linha inteira. Os campos ficam todos
   na `.grid-2` (duas colunas iguais, a mesma grelha dos pagamentos). */
.perfil-cabeca {
  display: grid; grid-template-columns: 150px minmax(0, 1fr);
  gap: 16px 24px; align-items: start;
  padding-bottom: 14px; border-bottom: 1px solid var(--line);
}
/* `#photo-card` traz `grid-row: span 2` do editor do CV (a foto abrange as duas linhas do nome e
   do título profissional): aqui abria uma segunda linha vazia por baixo da cabeça. */
.perfil-cabeca #photo-card { grid-row: auto; align-self: start; margin: 0; }
.perfil-nome { margin: 0 0 3px; font-size: 15px; font-weight: 700; color: var(--ink-900); }
/* O campo comprido volta a ocupar a linha inteira: `.largo` é a palavra que o `.dados-grid` já usa
   para isto (`grid-column: 1 / -1`), e vale dentro de qualquer grelha de duas colunas. */
.grid-2 > .largo { grid-column: 1 / -1; }
/* O `.form-section-title` traz 4px de folga em baixo, e a etiqueta do primeiro campo cola-se-lhe.
   8px é o que separa o título da fila sem a afastar da secção que ele abre. */
.form-section-title + .grid-2,
.form-section-title + .muted { margin-top: 8px; }
@media (max-width: 640px) {
  .perfil-cabeca { grid-template-columns: minmax(0, 1fr); }
}
/* A célula da foto abrange as DUAS linhas dos campos à direita (nome e título) e o
   quadrado estica-se até ao fundo delas: a caixa fica com a altura dos dois, como no
   print dele. */
#photo-card { display: flex; flex-direction: column; gap: 6px; margin: 0 0 14px; grid-row: span 2; align-self: stretch; }
/* O `display: flex` ganhava ao `hidden` que o `fetch` dos estilos põe: a foto ficava
   à vista nos modelos que não mostram foto. O `hidden` é um atributo, não um aviso. */
#photo-card[hidden] { display: none; }
/* O rótulo «Foto» com a folga de 6px do `gap` do cartão, e não com as duas (a do
   rótulo mais a do `gap`): somadas davam 12px e o quadrado começava 6px abaixo do
   input do nome — o print dele alinha-os. */
#photo-card .foto-label { margin-bottom: 0; }
#photo-card #photo-current { position: absolute; inset: 0; margin: 0; }
#photo-card .photo-thumb { position: absolute; inset: 0; }
#photo-card .photo-preview { width: 100%; height: 100%; border-radius: 0; object-fit: cover; border: 0; display: block; margin: 0; }
#photo-card .photo-pick {
  position: relative; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  width: 100%; max-width: 150px; aspect-ratio: 1 / 1; flex: 1 1 auto; min-height: 0;
  padding: 0; margin: 0; border-radius: 12px; border: 1px solid var(--line);
  background: var(--paper-soft); color: var(--ink-500); cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
  user-select: none;
}
#photo-card .photo-pick svg { width: 34px; height: 34px; }
#photo-card.com-foto .photo-pick { border-style: solid; border-color: var(--line); background: var(--card); }
#photo-card.com-foto .photo-pick > svg { display: none; }
#photo-card .photo-pick:hover, #photo-card .photo-pick:focus-visible { border-color: var(--green); color: var(--green-dark); }
#photo-card .photo-pick.drag { border-color: var(--green); background: var(--green-soft); color: var(--green-dark); }
/* A cruz vive por dentro do quadrado (o quadrado tem `overflow: hidden`, por isso
   fora do canto ela ficava cortada a meio). */
#photo-card .photo-x { top: 6px; right: 6px; }
/* O recorte abre SOBRE a página, como um diálogo de verdade — e não dentro da grelha.
   Em linha, o quadro de 240px tomava a largura toda da célula da foto e as linhas por
   baixo (nome, título, email...) desciam, para voltarem a subir no «Pronto»: a caixa
   da foto crescia e o formulário saltava. Sobreposto, o que está atrás não se mexe.
   As medidas seguem o `.modal-backdrop` do modal de pré-visualização (fundo a 62%). */
#photo-card .cropper-wrap {
  position: fixed; inset: 0; z-index: 90;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; padding: 18px;
  background: rgba(13, 20, 32, 0.62);
}
#photo-card .cropper-wrap[hidden] { display: none; }
#photo-card .cropper-wrap canvas {
  width: min(240px, 70vw); max-width: none; height: auto; aspect-ratio: 1 / 1;
  border-radius: 12px; background: var(--card); touch-action: none;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.28);
}
/* Zoom, «Girar» e «Pronto» na mesma pastilha por baixo do quadro: no telemóvel
   quebram linha dentro dela, sem empurrar nada nem sair do ecrã. */
#photo-card .cropper-controls {
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap;
  gap: 12px; margin: 0; padding: 10px 14px;
  background: var(--card); border-radius: 12px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.28);
}
#photo-card .cropper-controls label { flex-direction: row; align-items: center; gap: 8px; }
#photo-card .cropper-zoom input[type="range"] { width: 140px; }
#photo-card #photo-status { margin: 0; }

/* Afiliado */
.mini-input { width: 76px; padding: 8px 10px; border: 1.5px solid var(--line); border-radius: 8px; font-size: 13px; }
.chk-inline { display: flex; gap: 6px; align-items: center; font-size: 13px; }
/* `.field label` dá `display: block` a todas as etiquetas, e o `.field input` dá-lhes a
   largura toda: numa escolha (`checkbox`/`radio`) isso punha o visto numa linha e o
   texto por baixo. Aqui volta a ser `auto` (e em linha, com o texto ao lado). */
.field label.chk-inline { display: flex; align-items: flex-start; gap: 8px; }
/* Com duas ou três linhas de texto, o `align-items: center` do `.chk-inline` punha o
   visto a meio do parágrafo (medido: 25px abaixo do topo numa etiqueta de 63px, a
   520px de largura). Fica alinhado com a PRIMEIRA linha, que é onde se lê. */
.field label.chk-inline input { margin: 2px 0 0; }
.field input[type="checkbox"],
.field input[type="radio"] { width: auto; margin: 0; flex: none; accent-color: var(--green); }
/* Checklist da candidatura a afiliado (onde vai divulgar): cartões numa grelha que se
   marcam, com o mesmo idioma do `.path-opt` (`:has(:checked)`) — era uma fila de 8
   etiquetas soltas. O contorno é `box-shadow: inset` e nunca `border` (soma à caixa). */
.chk-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 8px; }
.chk-card {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 10px 12px;
  border-radius: 12px;
  background: var(--card);
  box-shadow: inset 0 0 0 1.5px var(--line);
  color: var(--ink-900);
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
}
.chk-card:hover { box-shadow: inset 0 0 0 1.5px var(--line-strong); }
.chk-card:has(input:checked) {
  background: var(--green-soft);
  box-shadow: inset 0 0 0 1.5px var(--green);
  color: var(--green-dark);
}
.chk-card:has(input:focus-visible) { box-shadow: inset 0 0 0 2px var(--green); }
/* Cada canal escolhido abre a caixa do seu @ — a MESMA regra do `.path-panel` (`:has`),
   sem guião: sem JavaScript escolhe-se o canal e o campo aparece na mesma. */
.chk-item { display: flex; flex-direction: column; gap: 6px; }
.chk-item .chk-pedido { display: none; padding: 0 2px 4px; }
.chk-item:has(input:checked) .chk-pedido { display: block; }
.chk-item .chk-pedido label { display: block; font-size: 12.5px; font-weight: 600; margin-bottom: 4px; color: var(--ink-900); }
.chk-item .chk-pedido input { width: 100%; }
.aff-link-edit { display: flex; flex-direction: column; gap: 4px; align-items: flex-start; min-width: 200px; }
.aff-link-edit .mini-input { width: 140px; }
.badge-grey { background: #eceef1; color: var(--muted); }
.aff-link code { display: inline-block; background: #f0f3f6; border: 1px solid var(--line); border-radius: 8px; padding: 8px 12px; font-size: 13px; word-break: break-all; }
.payout-form { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; }
.payout-form .field { flex: 1 1 300px; margin: 0; }
.payout-hint { flex: 1 1 100%; margin-top: 2px; }
/* O `.plain-list li` é flex com `space-between` (feito para listas de rótulo/valor) e
   numa frase isso parte-a em duas: o `<strong>10%</strong>` fica encostado à esquerda e
   o resto do texto empurrado para a direita, com um vão no meio. Aqui cada linha lê-se
   de seguida — número e frase —, com a mesma forma da lista ao lado («O que esperamos»). */
.stats li { display: block; margin-bottom: 8px; }
.stats li strong { color: var(--green-dark); font-weight: 800; white-space: nowrap; }

/* ---------- Afiliados na gestão: sub-navegação, fila e ficha ---------- */
/* São três áreas (candidaturas, contas, dinheiro) em páginas separadas: numa página só,
   as três tabelas competiam pela atenção e não se sabia onde estava o quê. */
.admin-tabs { display: flex; flex-wrap: wrap; gap: 6px; list-style: none; margin: 0 0 16px; padding: 0; }
.admin-tab { display: inline-flex; align-items: center; gap: 8px; padding: 8px 14px; border-radius: 10px; font-size: 13.5px; font-weight: 700; color: var(--ink-700); text-decoration: none; box-shadow: inset 0 0 0 1.5px var(--line); transition: box-shadow 0.15s, color 0.15s; }
.admin-tab:hover { box-shadow: inset 0 0 0 1.5px var(--green); color: var(--green-dark); }
.admin-tab.is-active { background: var(--ink-950); color: #fff; box-shadow: none; }
.admin-tab-n { font-size: 11px; font-weight: 800; padding: 1px 7px; border-radius: 999px; background: var(--green-soft); color: var(--green-dark); }
.admin-tab.is-active .admin-tab-n { background: rgba(255,255,255,0.2); color: #fff; }
/* ── Barra de filtros dos Documentos ─────────────────────────────────────────
   Era três ilhas empilhadas (tabs / formulário / tabs) com 16px entre elas e,
   dentro, três alturas (tab 37px, input 42px, botão 30px) e duas escalas
   tipográficas. Agora é um bloco só, com a mesma altura em tudo: 44px para a
   pesquisa e para cada opção do segmentado.

   A pesquisa tem a lupa DENTRO do campo (`.doc-search-ico`, à esquerda, e o
   input com `padding-left` para o texto não ir por baixo dela) em vez de uma
   etiqueta por cima: numa barra de filtros a etiqueta come 20px de altura e
   empurra a linha toda para baixo, e o que se quer é que a pessoa veja logo o
   campo. */
.doc-filters {
  margin: 0 0 18px;
  padding: 13px 16px 14px;
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: inset 0 0 0 1.5px var(--line);
}
.doc-filters-top { display: flex; align-items: center; gap: 12px; }
.doc-search { position: relative; flex: 1 1 auto; min-width: 0; }
.doc-search-ico {
  position: absolute; left: 13px; top: 50%; transform: translateY(-50%);
  color: var(--muted); pointer-events: none; /* a lupa não rouba o clique ao campo */
}
.doc-search input {
  width: 100%;
  height: 40px; /* a MESMA altura das opções do segmentado */
  padding: 0 13px 0 38px; /* 38 = 13 (padding) + 17 (lupa) + 8 de folga */
  border: 1.5px solid var(--line);
  border-radius: 10px;
  background: #fff;
  font-size: 14px;
  font-family: inherit;
  color: var(--ink-900);
  transition: border-color 0.15s, box-shadow 0.15s;
}
.doc-search input:focus {
  outline: none;
  border-color: var(--green);
  box-shadow: 0 0 0 3px rgba(14, 138, 94, 0.14);
}
.doc-search input::-webkit-search-cancel-button { cursor: pointer; }
.doc-filters-clear {
  flex: none;
  padding: 0 12px;
  height: 40px; /* alinhado com o campo, pelo centro */
  display: inline-flex; align-items: center;
  font-size: 13.5px; font-weight: 700;
  color: var(--muted);
  text-decoration: none;
  border-radius: 10px;
  transition: color 0.15s, background 0.15s;
}
.doc-filters-clear:hover { color: var(--red); background: #fdecea; }

/* Os três grupos lado a lado, cada um com a SUA legenda. Antes eram seis
   pílulas seguidas numa `<ul>` sem nome nenhum: não se percebia onde acabava o
   filtro de produto e começava o de dono.

   Os três grupos não cabem numa linha (medido: 1223px de opções para 984px de
   barra), e a quebra é o que há: o «Estado» é o filtro principal e leva a linha
   dele, e os dois secundários — «Produto» e «Conta» — ficam juntos na linha de
   baixo, à esquerda. Tive-os primeiro à direita, com `margin-left: auto` no
   último, e ficava uma linha só com o «Conta» pendurada ao canto; juntos leem-se
   como um par. */
.doc-segs { display: flex; flex-wrap: wrap; gap: 11px 22px; margin-top: 12px; }
.seg { margin: 0; padding: 0; border: 0; min-width: 0; }
.seg legend {
  padding: 0;
  margin-bottom: 6px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}
.seg-row { display: inline-flex; gap: 6px; }
/* O rádio fica escondido e é a `<span>` que se pinta — o mesmo truque do
   `.chk-card` do pedido de afiliado. `label` dá o clique e o foco por teclado;
   o `:focus-visible` volta a mostrar o contorno para quem navega por teclado. */
.seg-i { position: relative; cursor: pointer; }
.seg-i input { position: absolute; opacity: 0; pointer-events: none; }
.seg-i span {
  display: inline-flex; align-items: center; gap: 6px;
  height: 40px; padding: 0 14px;
  border-radius: 10px;
  background: #fff;
  box-shadow: inset 0 0 0 1.5px var(--line);
  font-size: 14px; font-weight: 700;
  color: var(--ink-700);
  white-space: nowrap;
  transition: box-shadow 0.15s, color 0.15s, background 0.15s;
}
.seg-i:hover span { box-shadow: inset 0 0 0 1.5px var(--green); color: var(--green-dark); }
.seg-i input:checked + span { background: var(--ink-950); color: #fff; box-shadow: none; }
.seg-i input:focus-visible + span { box-shadow: 0 0 0 3px rgba(14, 138, 94, 0.3); }
.seg-n {
  font-size: 11px; font-weight: 800; line-height: 1;
  padding: 3px 6px; border-radius: 999px;
  background: var(--green-soft); color: var(--green-dark);
}
.seg-i input:checked + span .seg-n { background: rgba(255, 255, 255, 0.22); color: #fff; }
.doc-filters-go { margin-top: 12px; }
/* Em ecrãs estreitos a legenda continua por cima da linha de opções e os
   grupos partem de inteiro; abaixo dos 900px a barra já não cabe em duas
   colunas e cada grupo ocupa a linha toda. */
@media (max-width: 900px) {
  .doc-segs { flex-direction: column; gap: 12px; }
  .seg-row { flex-wrap: wrap; }
}

/* Lista de Documentos. A coluna da selecção é a PRIMEIRA e é a mais estreita de
   todas (40px, o que a mão precisa para clicar). As cinco colunas estreitas
   seguintes (produto, estado, pronto, pedidos e ações) são FIXAS e não partem a
   linha: a etiqueta de estado e o botão de apagar têm de estar no mesmo sítio
   em todas as linhas, e o `white-space: nowrap` herdado da `table[data-cards]` era
   o que as fazia dançar quando um email era mais comprido que outro. As duas que
   decidem sozinhas — Documento e Quem — podem partir, e é isso que resolve a
   transborda: com elas a partir, a tabela cabe nos 912px que a área do
   backoffice dá a uma janela de 1021px, a mais estreita em que ainda é
   tabela (abaixo disso a `table[data-cards]` empilha em cartões).
   Os índices vão de 1 (selecção) a 8 (ações) — a inserção da coluna deslocou
   todos, e por isso a regra lista cada um por extenso em vez de contar. */
.docs-table .docs-pick input[type="checkbox"] { width: 18px; height: 18px; margin: 0; accent-color: var(--green); }
/* Estas larguras e `nowrap` só valem na TABELA a sério, a partir dos 1020px.
   Abaixo disso a `table[data-cards]` empilha em cartões (grelha) e um
   `width: 1%` num item de grelha colapsa a célula para ~2px: os badges e os
   ícones, que não encolhem, transbordavam por cima das células vizinhas — os
   «textos e ícones a quebrar» do telemóvel. Em cartão manda o bloco de baixo. */
@media (min-width: 1021px) {
  .docs-table .docs-pick { width: 40px; padding-left: 4px; padding-right: 4px; }
  .docs-table th:nth-child(3), .docs-table td:nth-child(3),
  .docs-table th:nth-child(4), .docs-table td:nth-child(4),
  .docs-table th:nth-child(5), .docs-table td:nth-child(5),
  .docs-table th:nth-child(7), .docs-table td:nth-child(7) { width: 1%; }
  /* A coluna das ações leva três botões de 34px e dois rasgos de 8px = 118px de
     conteúdo. Com o `width: 1%` dos badges, a tabela (que é `width: 100%`) era
     forçada a encolhê-la até 16px: os ícones espremiam-se para 20px ou
     transbordavam para fora da célula. Uma largura fixa resolve. */
  .docs-table th:nth-child(8), .docs-table td:nth-child(8) { width: 134px; }
  .docs-table th:nth-child(2), .docs-table td:nth-child(2),
  .docs-table th:nth-child(6), .docs-table td:nth-child(6) { white-space: normal; }
  /* Uma palavra que não parte (o nome «Bruno_chipitula_chissola» tem 24 caracteres
     e nenhum espaço) é a pior coisa que pode entrar nestas duas colunas: o browser
     não a consegue partir, dá-lhe a largura inteira e a tabela transborda (medido:
     980px de tabela para 966px de área, e o browser chegava a encolher a coluna da
     selecção a 26px, por baixo dos 18px da caixa). `overflow-wrap: anywhere` deixa
     o texto partir em qualquer ponto em vez de empurrar a tabela. */
  .docs-table td:nth-child(2), .docs-table td:nth-child(6) { overflow-wrap: anywhere; }
}

/* Cartão de telemóvel. A caixa de selecção sai do fluxo e vai para o canto
   (o rótulo «Selecionar» desaparece — a caixa já tem `aria-label`), o nome e o
   contacto ocupam a largura toda, e os restantes campos emparelham em duas
   colunas: Produto|Estado e Pronto|Pedidos. Sem isto o nome dividia a primeira
   linha com uma caixa solta e as ações ficavam espremidas contra badges. */
@media (max-width: 1020px) {
  .docs-table tr { position: relative; }
  .docs-table td.docs-pick { position: absolute; top: 12px; right: 12px; width: auto; padding: 0; }
  table.docs-table td.docs-pick::before { content: none; }
  /* O nome e o contacto ocupam a largura toda; os quatro campos pequenos
     emparelham em duas colunas (Produto|Estado e Pronto|Pedidos) e as ações
     fecham o cartão. O `order` é o que os junta: sem ele o «Quem» cai no meio
     da grelha e deixa buracos ao lado do «Pronto» e do «Pedidos». */
  .docs-table td[data-label="Documento"] { grid-column: 1 / -1; padding-right: 34px; order: 1; }
  .docs-table td[data-label="Produto"],
  .docs-table td[data-label="Estado"],
  .docs-table td[data-label="Pronto"],
  .docs-table td[data-label="Pedidos"] { order: 2; }
  .docs-table td[data-label="Produto"],
  .docs-table td[data-label="Pronto"] { grid-column: 1; }
  .docs-table td[data-label="Estado"],
  .docs-table td[data-label="Pedidos"] { grid-column: 2; }
  .docs-table td[data-label="Quem"] { grid-column: 1 / -1; order: 3; }
  .docs-table td[data-label="Ações"] { order: 4; }
  .docs-table td[data-label="Documento"],
  .docs-table td[data-label="Quem"] { white-space: normal; overflow-wrap: anywhere; }
  /* Num cartão de grelha o badge, sendo item de coluna, esticava pela largura
     toda e virava uma barra («CV» com 126px). Fica colado ao início. */
  .docs-table td .badge { align-self: flex-start; }
}
/* A barra de acções em massa: fica depois da tabela (não colada ao topo) e o
   botão só existe para quando há algo marcado — o `disabled` no HTML é o que
   segura a página sem JavaScript, e o JS é que o solta. */
.bulk-bar { display: flex; align-items: center; gap: 12px; margin: 14px 0 0; padding-top: 14px; border-top: 1px solid var(--line); }
.bulk-bar .btn[disabled] { opacity: .45; cursor: not-allowed; }

/* A fila (candidaturas e levantamentos): o texto cresce, o lado dos contactos fica fixo.
   Abaixo de 760px passa a coluna — o lado levava ~190px e o nome ficava espremido.
   O recuo de 12px à esquerda é de TODAS as linhas: é ali que a barra das novas se pinta
   sem empurrar o texto delas para a direita (com o recuo só nas novas, a coluna dos
   nomes ficava em dente de serra: 242 contra 230 nas outras cinco). */
.aff-queue .aff-item { display: flex; align-items: flex-start; gap: 16px; padding: 12px 0 12px 12px; }
.aff-item-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.aff-item-name { font-weight: 700; color: var(--ink-900); text-decoration: none; }
a.aff-item-name:hover { text-decoration: underline; text-underline-offset: 3px; }
.aff-item-side { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; gap: 5px; text-align: right; }
.aff-item-phone { font-weight: 700; color: var(--green-dark); text-decoration: none; }
.aff-item-phone:hover { text-decoration: underline; text-underline-offset: 3px; }
/* Por decidir: uma barra dourada, para a fila se ler de longe. */
.aff-item.is-new { box-shadow: inset 3px 0 0 0 var(--gold); }

/* As já decididas ficam fechadas no fim: a fila é para decidir. Mesmo padrão da lista
   das contas — uma linha que abre (sem guião). */
.aff-closed { margin-top: 18px; border-top: 1px dashed var(--line); }
.aff-closed > summary {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 0; cursor: pointer; list-style: none;
  font-size: 13px; font-weight: 700; color: var(--green-dark);
}
.aff-closed > summary::-webkit-details-marker { display: none; }
.aff-closed-close { display: none; }
.aff-closed[open] > summary .aff-closed-open { display: none; }
.aff-closed[open] > summary .aff-closed-close { display: inline; }

/* Contas: listagem primeiro e o formulário só na conta que se abre (como nos
   Parâmetros). Antes estavam TODOS os formulários abertos ao mesmo tempo — com meia
   dúzia de contas, a página era um muro de campos. `<details>` faz isto sem guião. */
.aff-rows { list-style: none; margin: 0; padding: 0; }
.aff-row { border-bottom: 1px dashed var(--line); }
.aff-row:last-child { border-bottom: 0; }
/* A linha é uma LISTAGEM: colunas fixas e as mesmas células em todas as linhas (a mesma
   lição da página das contas — em flex de larguras automáticas, o nome/código/% de cada
   conta empurravam o estado e os botões para posições diferentes).
   O «Copiar» fica na LINHA, não só dentro do formulário: é o que mais se faz com uma
   conta de afiliado e não devia obrigar a abrir. Um `button` dentro de um `summary` não
   abre/fecha o `<details>` (conteúdo interativo) e o `stopPropagation` garante-o. */
.aff-row details > summary {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 150px 90px 110px 140px;
  grid-template-areas: "conta codigo taxa estado acoes";
  gap: 4px 14px;
  align-items: center;
  padding: 12px 0;
  cursor: pointer;
  list-style: none;
}
.aff-row details > summary::-webkit-details-marker { display: none; }
.aff-row details[open] > summary { border-bottom: 1px dashed var(--line); }
.aff-col-conta { grid-area: conta; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.aff-col-codigo { grid-area: codigo; font-size: 12.5px; color: var(--muted); overflow-wrap: anywhere; }
.aff-col-taxa { grid-area: taxa; font-weight: 700; color: var(--green-dark); }
.aff-row details > summary .badge { grid-area: estado; justify-self: start; }
.aff-col-acoes { grid-area: acoes; display: flex; align-items: center; justify-content: flex-end; gap: 10px; }
.aff-sum-copy { white-space: nowrap; }
.aff-sum-name { font-weight: 700; color: var(--ink-900); overflow-wrap: anywhere; }
.aff-row details[open] .aff-sum-name { color: var(--green-dark); }
.aff-sum-toggle { font-size: 13px; font-weight: 700; color: var(--green-dark); white-space: nowrap; }
.aff-sum-toggle .aff-sum-close { display: none; }
.aff-row details[open] .aff-sum-toggle .aff-sum-open { display: none; }
.aff-row details[open] .aff-sum-toggle .aff-sum-close { display: inline; }
/* Abaixo de 1024px as cinco colunas já não respiram → três linhas por conta. */
@media (max-width: 1024px) {
  .aff-row details > summary {
    grid-template-columns: minmax(0, 1fr) 110px;
    grid-template-areas: "conta estado" "codigo taxa" "acoes acoes";
    align-items: start;
  }
  .aff-col-acoes { justify-content: flex-start; }
}
.aff-form { display: flex; flex-direction: column; gap: 12px; padding: 12px 0 16px; }
.aff-form-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.aff-form-fields .field { margin: 0; }
.aff-form-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.aff-form-link { margin-right: auto; font-size: 12.5px; color: var(--muted); overflow-wrap: anywhere; }

.aff-terms-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 14px; }

/* Contas registadas: é uma LISTAGEM, por isso as colunas têm de bater de linha para
   linha — daí uma grelha com áreas nomeadas e sempre as mesmas células em todas as
   linhas (com «—» onde não há nada). Em flex de larguras automáticas, a linha com
   «0 CVs» e a linha com «31 CVs · 1 candidatura» punham o estado e o botão em sítios
   diferentes, e lia-se como desalinhado. */
/* ⚠️ `.plain-list li` (0,1,1) vence um `.acct-row` sozinho (0,1,0): sem o `.plain-list`
   à frente, a linha continuava `display: flex` e as colunas ficavam desalinhadas SEM
   erro nenhum (foi o medir dos x que o mostrou). */
.plain-list .acct-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 168px 150px 104px 84px;
  grid-template-areas: "quem numeros datas estado acao";
  gap: 4px 14px;
  align-items: center;
}
.acct-quem { grid-area: quem; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.acct-name { font-weight: 700; color: var(--ink-900); overflow-wrap: anywhere; }
.acct-numeros { grid-area: numeros; }
.acct-datas { grid-area: datas; display: flex; flex-direction: column; gap: 2px; }
.acct-row .badge { grid-area: estado; justify-self: start; }
.acct-acao { grid-area: acao; justify-self: end; }
/* ⚠️ As colunas fixas precisam de ~736px: abaixo de ~1024px a coluna do nome ficava
   com 70px e o email partia-se em cinco linhas (167px de linha). E a coluna do estado
   tem de ser FIXA também aqui — com `auto`, cada linha (que é a sua própria grelha)
   calculava a largura do seu badge e os badges ficavam em x diferentes. */
@media (max-width: 1024px) {
  .plain-list .acct-row {
    grid-template-columns: minmax(0, 1fr) 104px;
    grid-template-areas: "quem estado" "numeros numeros" "datas acao";
    align-items: start;
  }
  .acct-datas { flex-direction: row; flex-wrap: wrap; gap: 2px 12px; }
}

/* Na ficha, o rótulo fica numa coluna e o valor logo a seguir. O `.kv` normal empurra o
   valor para a direita (`space-between`): num cartão largo o rótulo e o valor ficavam a
   350px um do outro e cada linha começava num x diferente — lia-se como uma tabela
   esticada, não como uma ficha. */
.aff-kv .kv li { display: grid; grid-template-columns: 128px minmax(0, 1fr); gap: 14px; align-items: baseline; }
.aff-kv .kv li strong { font-weight: 700; text-align: left; overflow-wrap: anywhere; }
@media (max-width: 560px) {
  .aff-kv .kv li { grid-template-columns: 104px minmax(0, 1fr); gap: 10px; }
}

/* ⚠️ Os campos desta ficha alinham pela linha do input, e para isso cada campo tem de
   ter o MESMO número de linhas de rótulo (texto + dica). Sem dica no «Como vai receber»,
   o input do lado — que a tinha — descia 24px. Ao acrescentar um campo, dar-lhe dica.

   ⚠️ E os valores decimais dentro de um `<input type="number">` têm de ir SEM localização:
   com `LANGUAGE_CODE = "pt-ao"`, `{{ valor }}` de um Decimal sai «10,00» e um
   `input[type=number]` com vírgula mostra-se VAZIO — parecia que não gravava. Nos
   templates da gestão usa-se `|unlocalize` (ver afiliado_candidatura.html e
   template_form.html). */

@media (max-width: 760px) {
  .aff-item { flex-direction: column; align-items: stretch; gap: 10px; }
  /* Em coluna, o lado também empilhava (badge + telefone + data + botão = 4 linhas
     debaixo do texto): passa a linha, que quebra sozinha. O item ia a 373px. */
  .aff-item-side { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 8px 12px; text-align: left; }
  .aff-item.is-new { box-shadow: inset 0 3px 0 0 var(--gold); padding-top: 12px; }
}
@media (max-width: 560px) {
  .aff-form-fields { grid-template-columns: 1fr; }
  .aff-sum-toggle { flex-basis: 100%; text-align: right; }
}

/* CVs por concluir em /cv/criar/: UMA linha só (a pedido — era um cartão com título,
   lista de até 6 linhas e link). Toda a linha é o link e o destino muda com o que
   existe: ver o `criar.html`. */
.draft-block { margin: 0 0 22px; border-left: 4px solid var(--gold); background: var(--gold-soft); border-radius: 10px; }
.draft-block a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 16px;
  color: var(--ink-950);
  font-size: 14.5px;
  font-weight: 600;
  text-decoration: none;
}
.draft-block a:hover { color: var(--green-dark); }
.draft-block .draft-cta { white-space: nowrap; font-weight: 700; }
.draft-block .draft-arrow { color: var(--gold-dark); font-weight: 700; }

/* ---------- Analítica (backoffice) ---------- */
.stat small { display: block; margin-top: 5px; color: var(--muted); font-size: 12px; }
.mono { font-family: var(--font-mono); font-size: 12.5px; }

.an-filters { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin-bottom: 18px; }
.an-chips { display: flex; gap: 4px; background: var(--paper-soft); border: 1.5px solid var(--line); border-radius: 999px; padding: 4px; }
.an-chip { padding: 5px 13px; border-radius: 999px; font-size: 13px; font-weight: 600; color: var(--muted); text-decoration: none; }
.an-chip:hover { color: var(--ink-900); }
.an-chip.is-on { background: var(--green); color: #fff; }
.an-toggle { display: inline-flex; align-items: center; gap: 7px; font-size: 13.5px; color: var(--ink-700); }
.an-toggle input { accent-color: var(--green); }

.an-chart { display: flex; align-items: flex-end; gap: 4px; height: 170px; margin: 8px 0 6px; }
.an-col { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; height: 100%; }
.an-bar { flex: 1; display: flex; flex-direction: column-reverse; justify-content: flex-start; gap: 1px; }
.an-humans { background: var(--green); border-radius: 3px; }
.an-bots { background: #c9cccc; border-radius: 3px; }
.an-day { height: 16px; font-size: 10.5px; color: var(--muted); text-align: center; white-space: nowrap; overflow: hidden; }
.an-dot { display: inline-block; width: 9px; height: 9px; border-radius: 3px; margin-right: 4px; }
.an-dot-humans { background: var(--green); }
.an-dot-bots { background: #c9cccc; margin-left: 10px; }

.an-funnel { display: flex; flex-wrap: wrap; gap: 10px; }
.an-step { flex: 1 1 110px; background: var(--paper-soft); border: 1px solid var(--line); border-radius: 10px; padding: 12px; text-align: center; }
.an-step strong { display: block; font-size: 24px; font-family: var(--font-display); line-height: 1.2; }
.an-step span { font-size: 11.5px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.4px; }
/* A percentagem de quem passou da etapa anterior. Sem isto o funil só dizia
   QUANTAS pessoas chegaram a cada passo; com os números crus, a queda entre
   «pessoas» e «abriram um documento» era um 46 que se lia como «não há
   problema» — e a perda estava logo a seguir ao número grande. */
.an-step em { display: block; margin-top: 2px; font-style: normal; font-size: 11px; color: var(--muted); font-family: var(--font-mono); }
.an-step.perdida em { color: #b3261e; font-weight: 600; }

.an-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(258px, 1fr)); gap: 16px; }
.an-list { list-style: none; margin: 0; padding: 0; }
.an-list li { display: flex; justify-content: space-between; gap: 10px; align-items: baseline; padding: 6px 0; border-bottom: 1px dashed var(--line); font-size: 13.5px; }
.an-list li:last-child { border-bottom: 0; }
.an-list b { flex: none; color: var(--ink-900); }
.an-list span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.an-sub { margin: 14px 0 2px; font-size: 12.5px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--muted); }

.an-timeline { list-style: none; margin: 0; padding: 0; }
.an-timeline li { display: flex; gap: 10px; align-items: baseline; padding: 6px 0; border-bottom: 1px dashed var(--line); font-size: 13.5px; }
.an-time { flex: none; width: 64px; color: var(--muted); font-family: var(--font-mono); font-size: 12px; }
.an-kind { flex: none; width: 128px; font-weight: 600; }
@media (max-width: 560px) {
  .an-chart { height: 128px; gap: 2px; }
  .an-kind { width: 92px; font-size: 12.5px; }
  .checkout-actions .checkout-edit { padding: 9px 14px; font-size: 13px; }
  .checkout-actions .checkout-edit-icon { display: none; }
  .checkout-actions .btn-block { padding: 12px 16px; font-size: 14.5px; }
}

/* A faixa de estilos é uma gaveta: o editor abre no trabalho (os campos) e a
   fila de modelos fica atrás do resumo. Fechada, o nome que o resumo mostra é a
   única pista de qual está escolhido — por isso ele é pintado com a cor do
   texto e não com a cor secundária do rótulo. */
.style-strip > summary { cursor: pointer; list-style: none; }
.style-strip > summary::-webkit-details-marker { display: none; }
.style-strip > summary .style-atual { font-weight: 600; color: var(--ink); }
.style-strip > summary::after { content: "▾"; margin-left: 6px; opacity: 0.55; }
.style-strip[open] > summary::after { content: "▴"; }

/* ===== Documentos — lista com menu de linha (Out/2026) =====================
   A tabela passou de oito colunas a cinco e as acções mudaram-se para um ⋮.
   As classes novas chamam-se `docs-*` de propósito: as regras antigas de
   `.docs-table` são `nth-child` que contam OITO colunas, e com cinco deixariam
   de bater certo. Nada é apagado — o `--lista` sobrepõe-se por especificidade.
   ======================================================================== */

.docs-table--lista thead th {
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted-light); font-weight: 600; white-space: nowrap;
}
.docs-table--lista tbody td { vertical-align: middle; }
.docs-table--lista tbody tr:hover { background: var(--paper-soft); }
.docs-table--lista .docs-th-actions { width: 64px; }

.docs-who { display: flex; align-items: center; gap: 12px; }
.docs-av {
  flex: none; width: 36px; height: 36px; border-radius: 50%;
  display: grid; place-items: center; font-weight: 600; font-size: 12px;
  background: var(--green-soft); color: var(--green-dark);
}
.docs-who-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.docs-nm { font-weight: 600; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.docs-tags { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 2px; }
.docs-date { font-variant-numeric: tabular-nums; color: var(--ink-700); white-space: nowrap; }
.docs-date--late { color: var(--red); font-weight: 600; }
.badge-warn { background: var(--gold-soft); color: var(--gold-dark); }

/* ---- o ⋮ ---- */
.docs-kebab { position: relative; display: inline-block; }
.docs-kebab > summary {
  list-style: none; width: 34px; height: 34px; border-radius: 9px;
  border: 1px solid transparent; display: grid; place-items: center;
  cursor: pointer; color: var(--muted);
}
.docs-kebab > summary::-webkit-details-marker { display: none; }
.docs-kebab > summary:hover, .docs-kebab[open] > summary {
  background: var(--paper); border-color: var(--line-strong); color: var(--ink-900);
}
.docs-menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 30;
  min-width: 244px; padding: 6px; background: var(--card);
  border: 1px solid var(--line-strong); border-radius: 12px; box-shadow: var(--shadow-lift);
  text-align: left;
}
.docs-menu a, .docs-menu-danger {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 10px; border: 0; border-radius: 8px; background: none;
  font: inherit; font-weight: 500; color: var(--ink-900); text-align: left; cursor: pointer;
  text-decoration: none; white-space: nowrap;
}
.docs-menu a:hover, .docs-menu-danger:hover { background: var(--paper); }
.docs-menu svg { flex: none; color: var(--muted); }
.docs-menu-hint { margin-left: auto; color: var(--muted-light); font-size: 12px; font-variant-numeric: tabular-nums; }
.docs-menu-sep { height: 1px; background: var(--line); margin: 6px 4px; }
.docs-menu-danger { color: var(--red); }
.docs-menu-danger:hover { background: #fdefec; }
.docs-menu-danger svg { color: var(--red); }
.docs-menu .inline-form { margin: 0; }

/* A data desce para a linha de baixo do estado.

   «Rascunho 15/01/2027» na mesma linha não cabe nos ~145px da coluna «Expira»:
   o texto passava por cima da coluna das ações e tapava o ⋮ — só os documentos
   SEM data (rascunhos sem expiração) deixavam o menu à vista. Medido: a data
   acabava em 1037 e a célula das ações começa em 994, e o ⋮ ficava por baixo
   do texto (Out/2026). */
.docs-table--lista td .docs-date {
  display: block;
  margin-top: 2px;
}

/* Nas duas últimas linhas o menu abre PARA CIMA: em baixo não há espaço e o
   painel da tabela cortava-o. CSS puro, sem JavaScript a medir alturas. */
.docs-table--lista tbody tr:nth-last-child(-n+2) .docs-menu { top: auto; bottom: calc(100% + 6px); }

/* A tecla «/» da procura. */
.doc-search { position: relative; }
.doc-search input { padding-right: 44px; }
.doc-search-key {
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  font: 600 11px/1 var(--font-body); color: var(--muted-light);
  border: 1px solid var(--line); border-radius: 6px; padding: 5px 7px; pointer-events: none;
}

@media (max-width: 1020px) {
  /* Em cartão (data-cards) a linha empilha: o ⋮ encosta à direita da célula e o
     menu deixa de ser flutuante — encostado à direita de tudo não caberia. */
  .docs-table--lista .docs-kebab { position: static; }
  .docs-table--lista .docs-menu { right: 0; left: auto; }
  .docs-av { width: 30px; height: 30px; font-size: 11px; }
}

/* ===== Documentos — corrige o alinhamento e as larguras (Out/2026) =========
   Dois defeitos vistos na pagina a serio:

   1. O `.actions-cell` antigo e `display: flex`. Num `<td>` isso tira a celula
      do alinhamento vertical da tabela e o ⋮ fica pendurado ao alto, com a
      linha da linha a passar-lhe por baixo. Dentro desta tabela a celula volta
      a ser celula, alinhada ao meio e encostada a direita.

   2. A coluna do cliente era a UNICA sem largura, e por isso levava sozinha
      todo o espaco que sobrava: o produto so comecava a 40% do painel. Agora a
      tabela e `fixed`, com larguras declaradas, e o que sobra vai para a ultima
      coluna — que e onde o browser ja poe as accoes encostadas a direita. O
      espaco morto deixa de estar entre o cliente e o produto, e passa a estar
      antes do ⋮, que e onde toda a gente o espera.

   Tudo dentro do `min-width: 1021px`: abaixo disso a tabela empilha em cartoes
   (`table[data-cards]`) e as larguras fixas colapsariam as celulas.
   ======================================================================== */
@media (min-width: 1021px) {
  .docs-table--lista { table-layout: fixed; }
  .docs-table--lista td.actions-cell {
    display: table-cell;
    vertical-align: middle;
    text-align: right;
  }
  .docs-table--lista th:nth-child(1), .docs-table--lista td:nth-child(1) { width: 44px; }
  .docs-table--lista th:nth-child(2), .docs-table--lista td:nth-child(2) { width: 360px; }
  .docs-table--lista th:nth-child(3), .docs-table--lista td:nth-child(3) { width: 108px; }
  .docs-table--lista th:nth-child(4), .docs-table--lista td:nth-child(4) { width: 118px; }
  .docs-table--lista th:nth-child(5), .docs-table--lista td:nth-child(5) { width: 150px; }
  /* A ultima fica sem largura de proposito: leva o resto. */
}

/* ===== Documentos — a coluna da conta e o cartao de telemovel (Out/2026) ===
   A coluna «Conta» voltou (estava na imagem e eu tinha-a escondido dentro da
   linha do cliente). Com sete colunas, as larguras do `--lista` mudam de sitio:
   a conta fica onde estava o produto e tudo o resto anda uma casa. Quem manda
   continua a ser a ultima coluna, que leva o resto.
   ======================================================================== */
@media (min-width: 1021px) {
  .docs-table--lista th:nth-child(3), .docs-table--lista td:nth-child(3) { width: 108px; }
  .docs-table--lista th:nth-child(4), .docs-table--lista td:nth-child(4) { width: 116px; }
  .docs-table--lista th:nth-child(5), .docs-table--lista td:nth-child(5) { width: 118px; }
  .docs-table--lista th:nth-child(6), .docs-table--lista td:nth-child(6) { width: 150px; }
  .docs-table--lista th:nth-child(7), .docs-table--lista td:nth-child(7) { width: auto; }
}

/* ---- o cartao do telemovel ----
   O bloco antigo (`@media max-width: 1020px`) esta preso a rotulos que ja nao
   existem — «Documento», «Estado», «Pronto», «Pedidos», «Quem». Sem rotulos,
   as celulas caiam na grelha sem ordem: o nome partilhava a linha com os
   distintivos, o produto e a data ficavam soltos e o ⋮ aparecia no meio. Aqui
   poem-se os rotulos que a tabela tem mesmo, e na ordem em que se leem.

   A grelha e de duas colunas: em cima quem e (o nome, o contacto e as
   etiquetas, de ponta a ponta, com espaco para a caixa de seleccao que esta
   fora do fluxo, no canto), depois os pares Produto|Conta e Criado|Expira, e
   por fim o menu, numa linha so para ele, encostado a direita. */
@media (max-width: 1020px) {
  .docs-table--lista td[data-label="Cliente"] {
    grid-column: 1 / -1;
    order: 1;
    padding-right: 34px;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .docs-table--lista td[data-label="Produto"],
  .docs-table--lista td[data-label="Conta"],
  .docs-table--lista td[data-label="Criado"],
  .docs-table--lista td[data-label="Expira"] { order: 2; }
  .docs-table--lista td[data-label="Produto"],
  .docs-table--lista td[data-label="Criado"] { grid-column: 1; }
  .docs-table--lista td[data-label="Conta"],
  .docs-table--lista td[data-label="Expira"] { grid-column: 2; }
  .docs-table--lista td[data-label="Ações"] {
    grid-column: 1 / -1;
    order: 3;
    text-align: right;
    border-top: 1px dashed var(--line);
    margin-top: 4px;
    padding-top: 8px;
  }
  /* O rotulo «Ações» ao lado de um ⋮ sozinho era ruido. */
  .docs-table--lista td[data-label="Ações"]::before { content: none; }
  /* O menu ancora no proprio ⋮ (no `tr` anchora-se o cartao inteiro, e em
     ecra de 390px o menu ia parar ao canto oposto). */
  .docs-table--lista .docs-kebab { position: relative; }
  .docs-table--lista .docs-menu { right: 0; left: auto; }
  .docs-table--lista .docs-who { align-items: flex-start; }
  .docs-av { width: 30px; height: 30px; font-size: 11px; }
}

/* ===== Documentos — a celula das accoes por classe (Out/2026) ==============
   `td[data-label="Ações"]` NAO pegava, enquanto todos os rotulos sem cedilha
   («Cliente», «Conta», «Criado», «Expira», «Produto») pegavam. E o `ç`: o
   atributo que o Django escreve e a cadeia do selector nao batem certo byte a
   byte (precomposto contra decomposto — o mesmo que parte nomes de ficheiros
   entre macOS e Linux). Regra que depende de acento morre calada.

   Aqui o selector passa a ser a CLASSE — `.actions-cell` — que e ASCII e nao
   depende de normalizacao nenhuma. Dentro do cartao a celula passa a ocupar a
   linha toda, com o ⋮ encostado a direita e um traco a separar.
   ======================================================================== */
@media (max-width: 1020px) {
  .docs-table--lista tr td.actions-cell {
    grid-column: 1 / -1;
    order: 3;
    text-align: right;
    justify-self: stretch;
    border-top: 1px dashed var(--line);
    margin-top: 4px;
    padding-top: 8px;
  }
  .docs-table--lista tr td.actions-cell::before { content: none; }
  .docs-table--lista tr td.actions-cell .docs-kebab { margin-left: auto; }
}

/* ===== Documentos — a coluna do cliente mais estreita (Out/2026) ===========
   Estava com 360px e o nome do cliente ocupa metade disso: a distancia ate ao
   produto voltava a notar-se. 300px chega para o nome, o contacto e as
   etiquetas, e o que sobra vai para o ⋮ (a ultima coluna), que e onde o espaco
   morto se le como intencao.

   E o «Ver o PDF» saia numa cor de link ja visitado, diferente dos vizinhos:
   dentro do menu, visitado ou nao, tem de ler-se igual.
   ======================================================================== */
@media (min-width: 1021px) {
  .docs-table--lista th:nth-child(2), .docs-table--lista td:nth-child(2) { width: 300px; }
}
.docs-menu a:visited { color: var(--ink-900); }

/* ===== Documentos — a coluna do contador de campos (Out/2026) ==============
   «falta a coluna de contador de campos preenchidos.» A coluna «Pronto» existia
   e eu tirei-a no redesenho; volta como contador: N/M, uma barra de 4px e a cor
   do estado (verde com secções, cinzento só com a ficha, vermelho sem o nome).
   O `title` traz o detalhe — «Falta o essencial: … · Experiência 3» — que antes
   era o texto todo da coluna e enchia a linha.

   Na carta não há contador: mostra o estado dela («✓ Completa»), como o código
   já decidia.

   Com oito colunas as larguras do `--lista` voltam a mudar de sitio. Quem leva
   o resto continua a ser a ultima, onde o ⋮ esta encostado a direita.
   ======================================================================== */
.docs-fill { display: inline-flex; flex-direction: column; gap: 5px; min-width: 74px; }
.docs-fill-n { font-weight: 600; font-variant-numeric: tabular-nums; color: var(--ink-900); font-size: 13.5px; }
.docs-fill-bar { display: block; height: 4px; border-radius: 99px; background: var(--line-strong); overflow: hidden; }
.docs-fill-bar > i { display: block; height: 100%; border-radius: 99px; background: var(--muted); }
.docs-fill-bar--green > i { background: var(--green); }
.docs-fill-bar--red > i { background: var(--red); }

@media (min-width: 1021px) {
  .docs-table--lista th:nth-child(3), .docs-table--lista td:nth-child(3) { width: 100px; }
  .docs-table--lista th:nth-child(4), .docs-table--lista td:nth-child(4) { width: 108px; }
  .docs-table--lista th:nth-child(5), .docs-table--lista td:nth-child(5) { width: 120px; }
  .docs-table--lista th:nth-child(6), .docs-table--lista td:nth-child(6) { width: 110px; }
  .docs-table--lista th:nth-child(7), .docs-table--lista td:nth-child(7) { width: 145px; }
  .docs-table--lista th:nth-child(8), .docs-table--lista td:nth-child(8) { width: auto; }
}

/* No cartão do telemóvel o contador entra no par do meio: Produto|Conta,
   Preenchido|Criado, e a data de expiração fecha em linha inteira. */
@media (max-width: 1020px) {
  .docs-table--lista td[data-label="Preenchido"] { order: 2; grid-column: 1; }
  .docs-table--lista td[data-label="Criado"] { order: 2; grid-column: 2; }
  .docs-table--lista td[data-label="Expira"] { order: 2; grid-column: 1 / -1; }
  .docs-table--lista td[data-label="Conta"] { order: 2; grid-column: 2; }
  .docs-table--lista td[data-label="Produto"] { order: 2; grid-column: 1; }
}

/* ===== Vagas (Fase 1) — ecras do backoffice (Out/2026) =====================
   Tudo dentro de `gestao_interna/`: nao ha uma linha de CSS para o site
   publico, porque nada disto aparece la.

   Os `th/td` da tabela das vagas levam padding proprio: as regras do
   `app.css` para tabelas sao escritas para a tabela dos documentos (oito
   colunas com `nth-child`), e uma tabela nova sem as suas proprias medidas
   herda alinhamentos que nao sao os dela.
   ======================================================================== */
.vaga-nums { display: flex; flex-wrap: wrap; gap: 18px; margin: 0 0 16px; }
.vaga-nums span { font-size: 13px; color: var(--muted); }
.vaga-nums b { color: var(--ink-900); font-size: 15px; }
.vaga-estado { display: flex; align-items: center; gap: 10px; }
.vaga-grid {
  display: grid; gap: 12px;
  /* 260px e nao 210: a 1016px de area o `auto-fit` dava quatro colunas, e o
     «Titulo da vaga» ficava na primeira linha, ao lado do email da empresa.
     Com 260 encaixam tres — empresa, telefone, email em cima; titulo,
     localizacao e regime em baixo. */
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
/* O campo cujo valor se sabe comprido ocupa a linha inteira (a grelha tem três
   colunas: um email, um nome de empresa ou uma morada num terço de linha cortam-se, e
   quem escreve não lê o que escreveu). O que é curto por natureza — NIF, telefone —
   continua a partilhar a linha. O nome da classe é o mesmo que o editor do CV já usa
   (`.campo-largo` no `.dados-grid`), para a casa ter uma palavra só para isto. Em telemóvel a grelha já é de uma coluna, isto não muda
   nada lá. */
.vaga-grid > .campo-largo { grid-column: 1 / -1; }

.vaga-form label { display: flex; flex-direction: column; gap: 5px; font-size: 12.5px; font-weight: 600; color: var(--ink-700); }
.vaga-form input, .vaga-form select, .vaga-form textarea {
  font: inherit; font-weight: 400; color: var(--ink-900);
  padding: 9px 11px; border: 1px solid var(--line-strong); border-radius: 10px; background: var(--card);
}
.vaga-form input:focus, .vaga-form select:focus, .vaga-form textarea:focus { outline: 2px solid var(--green); outline-offset: 1px; }
.vaga-wide { display: flex; flex-direction: column; gap: 5px; margin-top: 12px; }
.vaga-acoes { display: flex; align-items: center; gap: 14px; margin-top: 14px; }
.vaga-apagar { color: var(--red); border-color: var(--red); margin-top: 10px; }
.vaga-h3 { margin: 22px 0 8px; font-size: 14px; }
.vaga-busca { display: flex; gap: 8px; margin-bottom: 12px; }
.vaga-busca input { flex: 1 1 auto; font: inherit; padding: 9px 11px; border: 1px solid var(--line-strong); border-radius: 10px; }
.vaga-resultados { display: flex; flex-direction: column; gap: 8px; }
.vaga-resultado { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 9px 10px; border: 1px solid var(--line); border-radius: 10px; }
.vaga-resultado > div { flex: 1 1 200px; min-width: 0; display: flex; flex-direction: column; }
.vaga-resultado input[name="nota"] { flex: 0 1 190px; font: inherit; padding: 7px 9px; border: 1px solid var(--line-strong); border-radius: 8px; }
.vaga-inline { margin: 0; }
.vaga-inline select { font: inherit; padding: 6px 8px; border: 1px solid var(--line-strong); border-radius: 8px; background: var(--card); }
.vaga-consent { margin-top: 18px; border-top: 1px dashed var(--line); padding-top: 12px; }
.vaga-consent > summary { cursor: pointer; font-size: 12.5px; font-weight: 700; color: var(--green-dark); }
.vaga-table { width: 100%; }
.vaga-table th { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); text-align: left; padding: 8px 10px; white-space: nowrap; }
.vaga-table td { padding: 12px 10px; border-top: 1px solid var(--line); vertical-align: middle; }
.vaga-table td > form { margin: 0; }
/* A armadilha ja conhecida: `.actions-cell` e `display: flex` de outro ecra, e
   num `<td>` isso tira a celula do alinhamento vertical da tabela. */
.vaga-table .actions-cell { display: table-cell; vertical-align: middle; white-space: nowrap; }
.vaga-table .actions-cell .btn { margin-left: 6px; }
.vaga-table .actions-cell form.inline-form { display: inline-block; }

/* As acoes de uma linha alinhadas a direita: sem isto, uma linha que leva
   `select` + botao empurra o botao para a direita e as outras linhas (so com um
   botao) ficam noutra coluna. */
/* A lista das contas de uma empresa pode ser comprida e a coluna da acao leva
   um `select`: sem limite, o quadro sai do cartao e a lista aparece cortada. */
.vaga-table.acao-direita .vaga-inline select { max-width: 210px; }

/* Acoes no cabecalho, a direita do titulo. Os botoes levam todos as medidas do
   `.btn` normal: um `.btn-sm` ao lado parece de outra familia (foi o que se viu
   no «Editar vaga» com o «Fechar vaga»). */
.head-acoes { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.head-acoes .btn { padding: 11px 20px; font-size: 14.5px; border-radius: 11px; }

/* O cartao do que apaga: diz-se o que faz, e o botao fica sozinho. */
.card-perigo { border-color: rgba(200, 60, 60, .35); }

/* O campo de data nao herda a letra sozinho: quem escreve «dd/mm/aaaa» dentro
   dele e o editor do browser, que tem a sua propria fonte. */
/* A data. O `<input type="date">` desenha por dentro um controlo do browser
   (`::-webkit-datetime-edit`, com o `dd/mm/aaaa` e o ícone do calendário) que NÃO herda a
   fonte do campo — fica com a fonte da interface do Chrome, e com ela outra altura.
   Resultado: os campos de data saem do ritmo dos outros e empurram a fila do formulário.
   Esta regra existia, presa a `.vaga-form`; o formulário da vaga nova é um `.card` sem
   essa classe e nunca a recebia. Passa a valer para todo o site. */
/* O campo de data não se deixa medir: o controlo nativo tem tamanho próprio e há motores
   que ignoram o `width` (a caixa saía 48px além do cartão — o `padding` de 24px dele, dos
   dois lados). `width` e `max-width` sozinhos não chegaram. O que nenhum motor ignora é uma
   grelha de uma coluna: com `minmax(0, 1fr)` e `min-width: 0` a caixa não PODE passar a
   coluna, mesmo que o conteúdo nativo peça mais. O `:has()` apanha só os campos que têm um
   campo de data dentro — sem mexer em seis formulários. Onde o `:has()` não existir, ficam
   as regras de largura abaixo, que não pioram nada. */
.field:has(> input[type="date"]) {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}
/* A gestão usa rótulo em texto e campo na mesma linha («Começa em [campo]»): aqui a grelha
   é de duas colunas, para o campo caber sem perder a linha. */
.vaga-grid label:has(> input[type="date"]) {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 8px;
}
input[type="date"] {
  width: 100%;
  min-width: 0;
  max-width: 100%;
  box-sizing: border-box;
}
input[type="date"]::-webkit-datetime-edit { font: inherit; padding: 0; }
input[type="date"]::-webkit-calendar-picker-indicator { margin: 0; padding: 0; }
input[type="date"]::-webkit-date-and-time-value { text-align: left; min-height: 0; }

/* A ficha de um registo (a empresa): rotulo pequeno e valor por baixo, numa
   grelha — le-se de cima abaixo e cabe em qualquer largura. */
.ficha-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px 28px;
}
.ficha-item { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ficha-rot {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--muted);
}
.ficha-valor { font-size: 15px; overflow-wrap: anywhere; }

/* Dois botoes na mesma celula de acoes: sem isto ficam encostados. */
.actions-cell .btn + .btn { margin-left: 8px; }

/* Cada conta ligada a uma empresa, com o seu «Desligar» ao lado. */
.conta-ligada { display: inline-flex; align-items: center; gap: 8px; margin-right: 10px; }

.vaga-table.acao-direita .actions-cell { text-align: right; }
.vaga-table.acao-direita .actions-cell form.inline-form { margin-left: 8px; }

/* ===== Vagas publicas (Fase 1b) (Out/2026) =================================
   A unica parte das vagas que o site publico mostra. Reaproveita as classes da
   casa (`card`, `btn`, `badge`, `back-link`) e acrescenta so o cartao da lista.
   ========================================================================= */
/* A busca e os filtros da lista. Cada vaga é um cartão (`.vaga-cartao`), sem
   selo «Aberta» repetido nem borda pesada — o que se repetia em todas era ruído. */
.vaga-busca { display: flex; gap: 10px; align-items: stretch; margin-bottom: 12px; }
.vaga-busca input[type="search"] { flex: 1 1 auto; min-width: 0; }
.vaga-busca .btn { flex: 0 0 auto; }

/* Os filtros são pastilhas: ícone, o que está escolhido, e uma seta. Abrem em
   `details` (sem JavaScript) e cada opção é um link com os outros filtros
   lá dentro — um endereço filtrado partilha-se no WhatsApp tal como está. */
.vchips { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 14px; }
.vchip { position: relative; }
.vchip > summary {
  display: inline-flex; align-items: center; gap: 7px; list-style: none; cursor: pointer;
  padding: 7px 12px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--card); font-size: 13.5px; font-weight: 600; color: var(--ink-700);
}
.vchip > summary::-webkit-details-marker { display: none; }
.vchip > summary:hover { border-color: var(--green); }
.vchip[open] > summary { border-color: var(--green); }
.vchip.is-on > summary { background: var(--green-soft); border-color: var(--green); color: var(--green-dark); }
.vchip-caret { color: var(--muted-light); font-size: 11px; line-height: 1; }
.vchip-menu {
  position: absolute; z-index: 30; top: calc(100% + 6px); left: 0; min-width: 210px;
  max-height: 320px; overflow: auto; padding: 6px;
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 10px 30px rgba(20, 30, 50, .12);
}
.vchip-menu a { display: block; padding: 8px 10px; border-radius: 8px; color: var(--ink-900); text-decoration: none; font-size: 14px; }
.vchip-menu a:hover { background: var(--paper-soft); }
.vchip-menu a.is-on { background: var(--green-soft); color: var(--green-dark); font-weight: 600; }
.vchip-limpar { font-size: 13.5px; font-weight: 600; color: var(--green-dark); text-decoration: none; }

/* O ícone das linhas: 15px, traço fino, herda a cor do texto onde está. */
.vi { width: 15px; height: 15px; flex: 0 0 auto; fill: none; stroke: currentColor;
      stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }


/* ------------------------------- A lista da empresa: números, abas e cartões
   Os quatro números respondem a «como está isto?» sem sair da lista (não é um
   ecrã de resumo a mais, é a mesma página). As abas trazem a contagem dentro,
   para se ver o que há antes de clicar. Cada vaga é um cartão. */
.nums { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-bottom: 16px; }
.num { background: var(--card); border: 1px solid var(--line); border-radius: 14px; padding: 14px 16px; }
.num b { display: block; font-size: 26px; font-weight: 800; line-height: 1.1; color: var(--ink-900); }
.num span { display: block; margin-top: 4px; color: var(--muted); font-size: 13px; }

.abas-linha { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; margin-bottom: 16px; }

/* O gráfico do desempenho: barras de CSS, sem biblioteca e sem JavaScript. A largura
   vem da vista em percentagem; aqui é só o desenho. */
.abas-acoes { display: inline-flex; align-items: center; gap: 10px; }
.graf { list-style: none; margin: 8px 0 18px; padding: 0; display: grid; gap: 7px; }
.graf-linha { display: grid; grid-template-columns: 190px minmax(0, 1fr) 34px; align-items: center; gap: 10px; }
/* O rótulo parte em duas linhas em vez de cortar: «Informática e Tecno…» não diz
   nada a quem contrata, e os nomes das áreas são compridos. */
.graf-rot { font-size: 13px; color: var(--muted); overflow-wrap: anywhere; }
.graf-barra { display: block; height: 9px; background: var(--paper-soft); border-radius: 999px; overflow: hidden; }
.graf-barra i { display: block; height: 100%; background: var(--green); border-radius: 999px; }
.graf-n { font-size: 13px; text-align: right; }
.graf-par { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
@media (max-width: 780px) { .graf-par { grid-template-columns: 1fr; } }
@media (max-width: 620px) {
  .graf-linha { grid-template-columns: 120px minmax(0, 1fr) 30px; }
  .abas-acoes { width: 100%; justify-content: space-between; }
}
.abas {
  display: flex; gap: 4px; padding: 4px; overflow-x: auto;
  background: var(--paper-soft); border: 1.5px solid var(--line); border-radius: 999px;
}
.aba {
  display: inline-flex; align-items: center; gap: 7px; padding: 7px 14px; border-radius: 999px;
  font-size: 13.5px; font-weight: 600; color: var(--muted); text-decoration: none; white-space: nowrap;
}
.aba:hover { color: var(--ink-900); }
.aba.is-on { background: var(--green); color: #fff; }
.aba-n { padding: 1px 7px; border-radius: 999px; background: rgba(0, 0, 0, .06); font-size: 12px; font-weight: 700; }
.aba.is-on .aba-n { background: rgba(255, 255, 255, .24); color: #fff; }

.vagas-cartoes { display: grid; gap: 10px; }
.vaga-cartao {
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  padding: 16px 18px; background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  text-decoration: none; color: inherit;
  transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
.vaga-cartao:hover { border-color: var(--green); box-shadow: 0 6px 18px rgba(20, 30, 50, .06); transform: translateY(-1px); }
.vaga-cartao-txt { min-width: 0; }
.vaga-cartao-txt h2 { margin: 0; font-size: 19px; }
.vaga-cartao-meta { display: flex; flex-wrap: wrap; gap: 16px; margin: 7px 0 0; color: var(--muted); font-size: 13.5px; }
.vaga-cartao-meta span { display: inline-flex; align-items: center; gap: 6px; }
.vaga-cartao-fim { display: flex; align-items: center; gap: 14px; white-space: nowrap; }
.vaga-cartao-nota { display: inline-flex; align-items: center; gap: 7px; color: var(--muted); font-size: 13.5px; }
.vaga-cartao-ir {
  display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px;
  border: 1px solid var(--line); border-radius: 50%; background: var(--paper-soft); color: var(--green-dark);
}
.vaga-cartao:hover .vaga-cartao-ir { background: var(--green-soft); border-color: var(--green); }
.vaga-cartao-emp { margin: 3px 0 0; color: var(--ink-700); font-size: 14.5px; }
.vaga-cartao-desc {
  display: -webkit-box; overflow: hidden; margin: 6px 0 0;
  color: var(--muted); font-size: 13.5px;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.vaga-cartao .vi { width: 15px; height: 15px; flex: none; }
/* O ponto à frente do estado, no cartão: a cor do selo diz o estado à distância,
   e o ponto dá-lhe um «está ligado» que o texto sozinho não tem. */
.vaga-cartao .badge::before {
  content: ""; display: inline-block; width: 6px; height: 6px; margin-right: 6px;
  border-radius: 50%; background: currentColor; vertical-align: 1px;
}
.btn-nova { display: inline-flex; align-items: center; gap: 8px; }

/* A caixa da autorizacao: o texto do consentimento e o rotulo, por inteiro. */
.vaga-autorizo {
  display: flex; flex-direction: row; align-items: flex-start; gap: 10px;
  margin-top: 14px; padding: 12px 14px; font-weight: 400; font-size: 13.5px;
  background: var(--paper); border: 1px solid var(--line-strong); border-radius: 12px;
  color: var(--ink-900);
}
.vaga-autorizo input { margin-top: 2px; accent-color: var(--green); }
.vaga-versao { display: block; color: var(--muted-light); font-size: 11.5px; margin-top: 2px; }


/* ------------------------------------------------- A ficha da vaga da empresa
   Duas colunas: o conteúdo (descrição, requisitos, candidaturas) e um rail de
   factos que fica à vista enquanto se percorre a página. Num ecrã estreito o rail
   desce para baixo do conteúdo — sem `order` nem truques. */
.ficha-duas { display: grid; grid-template-columns: minmax(0, 1fr) 330px; gap: 18px; align-items: start; }
.ficha-conteudo { display: grid; gap: 14px; min-width: 0; }
.ficha-lado { display: grid; gap: 14px; position: sticky; top: 14px; }
.card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.card-head h2 { margin: 0; }
.card-head + * { margin-top: 10px; }
.h-mini { font-size: 15px; }
.texto-vaga { color: var(--ink-900); font-size: 15px; line-height: 1.6; }
.texto-vaga p { margin: 0 0 8px; }
.texto-vaga p:last-child { margin-bottom: 0; }

/* Os factos: rótulo à esquerda, valor à direita, uma linha cada. Lê-se de cima
   para baixo, sem grelha de etiquetas em maiúsculas a competir com o conteúdo. */
.fatos { list-style: none; margin: 12px 0 0; padding: 0; }
.fatos li {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 9px 0; border-bottom: 1px dashed var(--line); font-size: 14px;
}
.fatos li:last-child { border-bottom: 0; }
.fatos span { color: var(--muted); }
.fatos b { font-weight: 600; text-align: right; }
.estado-dito { margin-top: 10px; }

/* O apagar: no fim, explicado, e longe do «Editar» — não são a mesma decisão. */
.card-perigo { border-color: #f0d9d7; }
.card-perigo h2 { color: var(--red); }
/* O apagar: à direita do Editar e a vermelho, sempre — vê-se o que é sem ter de
   pousar o rato. Mesma medida e forma dos botões de contorno, para a linha não
   desalinhar; ao passar o rato ganha o fundo rosado da casa (`badge-red`). */
.btn-apagar { border-color: var(--red); color: var(--red); }
.btn-apagar:hover { background: #fdeceb; border-color: var(--red); color: var(--red); }

/* A lista das candidaturas presa a cinco: com trinta, a página era um scroll. */

/* ---------------------------------------------------------- As minhas candidaturas
   Nao existia nada para isto, e sem flex os botoes empilhavam-se a esquerda.
   O que o candidato ve tem de parecer tao cuidado como o resto do site. */
.cand-lista { display: grid; gap: 12px; }
.cand-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.cand-main { display: flex; flex-direction: column; gap: 2px; min-width: 260px; }
.cand-main b { font-size: 15px; }
.cand-acoes { display: flex; align-items: center; gap: 8px; }
.cand-acoes form { margin: 0; display: inline-flex; }
@media (max-width: 640px) {
  .cand-acoes { width: 100%; justify-content: flex-start; }
}


/* ---------------------------------------------- Partilhar a vaga (backoffice)
   O link tem de se poder copiar sem lá chegar com o rato: em Angola a vaga
   partilha-se por WhatsApp. */
.vaga-partilha { margin-top: 12px; display: grid; gap: 6px; max-width: 760px; }
.vaga-partilha-linha { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.vaga-partilha-linha input {
  flex: 1 1 300px;
  min-width: 0;
  font: inherit;
  font-size: 13px;
  padding: 9px 12px;
  border: 1px solid #ddd8ca;
  border-radius: 10px;
  background: #fff;
  color: inherit;
}


/* ------------------------------------------------- Pagina da empresa (token)
   Sem sessao e sem menu: quem abre isto e uma empresa a quem se mandou um link.
   Nao tem de perceber o site — tem de ver a vaga e os candidatos. */
.empresa-page { background: #f7f5ef; margin: 0; }
.empresa-wrap { max-width: 860px; margin: 0 auto; padding: 28px 20px 60px; }
.empresa-topo {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin-bottom: 22px;
}
.empresa-marca { font-size: 20px; font-weight: 700; letter-spacing: -0.2px; }
.empresa-marca em { color: #0e8a5e; font-style: normal; }
.empresa-wrap h1 { font-size: 24px; margin: 0 0 4px; }
.empresa-wrap h2 { font-size: 15px; margin: 26px 0 10px; }
.empresa-lista { display: grid; gap: 12px; }
.empresa-cand {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}
.empresa-cand-main { display: flex; flex-direction: column; gap: 2px; min-width: 240px; }
.empresa-nota {
  margin-top: 28px; padding-top: 16px; border-top: 1px solid #e6e1d4;
  color: #6c6a63; font-size: 12.5px; line-height: 1.55;
}
@media (max-width: 620px) {
  .empresa-cand-acoes { width: 100%; }
}

/* Filtros da lista de vagas. Sem JavaScript, tudo por GET — o endereco
   filtrado pode ser partilhado tal como esta. */
.vagas-filtro {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  margin: 0 0 0.75rem;
}
.vagas-filtro input,
.vagas-filtro select {
  /* As mesmas medidas dos campos do resto do site (.field): um campo da casa,
     nao um formulario de browser colado por cima. */
  padding: 11px 13px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 15px;
  font-family: inherit;
  color: var(--ink-900);
  background: #fff;
}
.vagas-filtro input:focus,
.vagas-filtro select:focus {
  outline: none;
  border-color: var(--green);
  box-shadow: 0 0 0 3px rgba(14, 138, 94, 0.14);
}
.vagas-filtro input[type="search"] {
  flex: 1 1 16rem;
  min-width: 0;
}
.vagas-filtro select {
  flex: 0 1 auto;
  max-width: 14rem;
}
@media (max-width: 620px) {
  .vagas-filtro input[type="search"],
  .vagas-filtro select {
    flex: 1 1 100%;
    max-width: none;
  }
  /* O botao acompanha os campos: alto como um campo (alvo de dedo) e com a
     largura da linha quando esta so, metade quando esta com o «Limpar». Sem
     isto o «Filtrar» ficava pequeno e encostado a esquerda, sozinho. */
  .vagas-filtro .btn-sm,
  .cand-painel .btn-sm {
    flex: 1 1 calc(50% - 0.25rem);
    min-height: 44px;
    font-size: 15px;
    border-radius: var(--radius-sm);
  }
}

/* Painel da empresa e barra de filtros: os campos e as acoes seguem as medidas
   da casa. O `.btn-sm` do site e um botao de contorno (serve para acoes
   secundarias); aqui as duas accoes principais precisam de ser verde solido, e
   o `select` precisa das medidas de `.field`, senao parece um formulario de
   browser colado por cima. Fica scoped de proposito: mexer no `.btn-sm` mudava
   paginas que nada tem a ver com isto. */
.vagas-filtro .btn-sm,
.cand-painel .btn-sm {
  background: var(--green);
  color: #fff;
  border: 0;
}
.vagas-filtro .btn-sm:hover,
.cand-painel .btn-sm:hover { background: var(--green-dark); }
.cand-painel select {
  padding: 8px 10px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: 14px;
  color: var(--ink-900);
  background: #fff;
}

/* A ficha da candidatura: uma lista de factos, com o nome e o estado em cima e as
   acoes em baixo. O template antigo usava `.admin-row`/`.admin-quem`/`.admin-acoes`,
   classes que nao existem em CSS nenhum: a data, o botao e o select empilhavam-se a
   toa. Cada classe nova aqui tem de existir neste ficheiro — ha teste. */
.cand-cabeca {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
.cand-cabeca > strong { font-size: 16px; }
/* A lista de factos: rotulo a esquerda, valor a direita, alinhados por coluna —
   e' o que deixa varrer os candidatos de cima a baixo. */
.cand-dados {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 4px;
}
.cand-dados > li {
  display: grid;
  grid-template-columns: 170px minmax(0, 1fr);
  gap: 12px;
  align-items: baseline;
}
.cand-rot { color: var(--muted); font-size: 13px; }
.cand-val { font-size: 14px; }
.cand-acoes {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  border-top: 1px dashed var(--line);
  padding-top: 10px;
}
.cand-acoes form { margin: 0; display: inline-flex; gap: 8px; }
/* O select do estado é um campo da casa como os outros, e sem isto era o select CRU do
   browser: medido a 1440px, Arial 13,3px, `padding: 0`, a borda cinzenta do sistema
   (`rgb(118,118,118)`) e 30px de altura — encostado a botões `.btn-sm`. As regras dos campos
   pedem `.field` ou `.vaga-form` (ver a regra dos campos, em cima), e nenhuma lhe chegava. As
   medidas aqui são as da FILA (o `.btn-sm` ao lado), não as do formulário: o select acompanha
   os botões. Os tokens são os da casa (`--line`, `--radius-sm`, `--ink-900`, `--green`). */
.cand-acoes select {
  padding: 7px 11px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-family: inherit;
  line-height: 1.3;
  color: var(--ink-900);
  background: #fff;
  max-width: 100%;
}
.cand-acoes select:focus {
  outline: none;
  border-color: var(--green);
  box-shadow: 0 0 0 3px rgba(14, 138, 94, 0.14);
}
/* Telemovel: o rotulo passa para cima do valor (duas colunas de 170px num ecra de
   390px deixam o valor com 100px). */
@media (max-width: 620px) {
  .cand-dados > li { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .cand-acoes { width: 100%; }
  /* Na fila estreita o select ocupa o que sobra, em vez de espremer «Guardar» para fora. */
  .cand-acoes select { flex: 1 1 auto; min-width: 0; }
}

/* O caret da barra da gestao. O `.caret` do site e dimensionado pelo contexto de
   cada menu; aqui o contexto e outro e o SVG saia no tamanho natural (enorme),
   empurrando os rotulos dos grupos para fora da barra. A barra da gestao e a
   unica `site-nav nav-drop`, por isso o alvo e este. */
.site-nav.nav-drop > .head-dropdown > .link > .caret {
  width: 13px;
  height: 13px;
  margin-left: 5px;
  vertical-align: -1px;
}

/* ---------- Telemóvel: a gestão lê-se e usa-se no telefone ---------- */
@media (max-width: 640px) {
  /* O cabeçalho empilha. Lado a lado, o texto ficava espremido a três palavras
     por linha e os botões saíam desnivelados (cada um com a sua largura). */
  .admin-head { flex-direction: column; align-items: stretch; }
  .admin-head h1,
  .cat-head h1,
  .dash-hello h1,
  .dash-title,
  .order-head h1,
  .pedido-h { font-size: 22px; }
  .admin-head > .btn { width: 100%; }

  /* Os botões do cabeçalho repartem a linha por igual: mesma largura, mesma
     altura, sem sobras desiguais à direita. */
  .head-acoes {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 8px;
    justify-content: stretch;
  }
  .head-acoes .btn { width: 100%; }
  .head-acoes form { display: flex; width: 100%; }
  .head-acoes form .btn { width: 100%; }


  /* A ficha em duas colunas: cabe, e a página fica a metade do comprimento. */
  .ficha-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 16px; }

  /* Os links de partilha: o campo ocupa a linha toda, os botões repartem a de
     baixo — em fila, o «Copiar o link» ficava sozinho e os outros dois abaixo. */
  .vaga-partilha-linha {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(88px, 1fr));
    gap: 8px;
  }
  .vaga-partilha-linha input { grid-column: 1 / -1; }
  .vaga-partilha-linha .btn { width: 100%; }

  /* A fila de botões dos formulários: repartida, não encostada à esquerda. */
  .vaga-acoes { flex-wrap: wrap; }
  .vaga-acoes .btn { flex: 1 1 0; }

  /* O botão da procura com a altura do campo (era um `btn-sm` ao lado de um
     `input` de 38px). */
  .vaga-busca .btn { min-height: 40px; }
}

/* Uma ficha de uma coluna: para valores compridos (um email) que aos 390px nao
   cabem em meia largura e partiam a meio da palavra. */
.ficha-grid.uma-coluna { grid-template-columns: 1fr; }

/* ---------------------------------------------------- A lista das vagas no telemóvel
   A busca e a linha passam a uma coluna; o prazo desce para baixo, com a seta à
   direita. A pastilha aberta empurra o conteúdo em vez de flutuar — num ecrã
   estreito um menu flutuante sai do campo de visão. */
@media (max-width: 620px) {
  .vaga-busca { flex-direction: column; }
  .vaga-busca .btn { width: 100%; }
  .vchip-menu { position: static; box-shadow: none; margin-top: 6px; min-width: 0; }
}

/* ---------------------------------------------- A ficha da vaga no telemóvel
   O rail desce para baixo do conteúdo (é o que a grelha faz por omissão) e a
   partilha empilha-se. */
@media (max-width: 1020px) {
  .ficha-duas { grid-template-columns: 1fr; }
  .ficha-lado { position: static; }
}
@media (max-width: 620px) {
  .ficha-lado .vaga-partilha-linha { flex-direction: column; align-items: stretch; }
  .fatos li { padding: 8px 0; }
}

/* ------------------------------------------- A lista da empresa no telemóvel
   Os números passam a duas colunas e o cartão empilha: o que estava à direita
   desce, com a seta no fim da linha. */
@media (max-width: 900px) {
  .nums { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  .vaga-cartao { flex-direction: column; align-items: stretch; gap: 12px; }
  .vaga-cartao-fim { justify-content: space-between; }
  .abas-linha { align-items: flex-start; }
}



/* O nome do documento com o olho ao lado (o checkout). */
.doc-linha { display: inline-flex; align-items: center; gap: 8px; }

/* A cabeça do cartão do documento (o checkout): o nome dele e o olho, na mesma
   linha nos dois ecrãs. É a «secção do olho». */
.preview-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.preview-head h2 { margin: 0; }
.doc-tipo { margin: 2px 0 0; }

/* A âncora da triagem (`?c=<pk>#candidaturas`, e o mesmo nas abas): sem isto a secção
   parava debaixo do cabeçalho `sticky` (63px medidos) e o título e as abas ficavam
   tapados. 76 = 63 do cabeçalho + 13 de folga. */
#candidaturas { scroll-margin-top: 76px; }

/* O cartão da pessoa escolhida. A regra vivia dentro de `.empresas-candidaturas`, e ao
   tirar o wrapper o painel ficou sem forma — o teste das classes apanhou-o. */
.cand-ficha {
  display: grid;
  gap: 10px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: #fff;
}

/* ---------------------------------------------------------- A triagem da vaga
   A fila à esquerda («quem são») e a pessoa escolhida à direita («quem é este»). Antes
   eram 30 fichas completas empilhadas — 10 328px medidos numa vaga com 30 candidaturas,
   com 30 selects e 30 botões iguais. A escolha é uma ligação (`?c=<pk>`), como o resto
   da área: sem JavaScript e com URL que se pode mandar a alguém. */
.cand-trabalho {
  display: grid;
  grid-template-columns: 320px minmax(0, 1fr);
  gap: 18px;
  align-items: start;
  margin-top: 14px;
}
.cand-fila {
  display: grid;
  gap: 3px;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--paper-soft);
  /* A fila acompanha o painel: com 30 nomes, quem percorre os detalhes não perde a
     lista de vista. O tecto é a janela, e a fila rola por dentro. */
  position: sticky;
  top: 14px;
  max-height: calc(100vh - 40px);
  overflow-y: auto;
}
.cand-fila-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 10px;
  border: 1px solid transparent;
  border-radius: 10px;
  text-decoration: none;
  color: inherit;
}
.cand-fila-item:hover { background: #fff; border-color: var(--line); }
.cand-fila-item.is-on {
  background: #fff;
  border-color: var(--green);
  box-shadow: 0 0 0 2px rgba(14, 138, 94, .12);
}
.cand-fila-quem { display: grid; gap: 1px; min-width: 0; }
.cand-fila-quem b { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cand-fila-meta { font-size: 12.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cand-fila-item .badge { flex: none; }
.cand-painel { display: grid; gap: 14px; min-width: 0; }

/* A dobra do desempenho: os números ficam no cabeçalho, à vista mesmo fechada; o
   gráfico abre a um clique. Fechada por omissão — nesta página veio-se ver pessoas. */
.card-dobra > summary {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  cursor: pointer;
  list-style: none;
  flex-wrap: wrap;
}
.card-dobra > summary::-webkit-details-marker { display: none; }
.card-dobra > summary h2 { margin: 0; }
.card-dobra > summary h2::after { content: " ▾"; color: var(--muted); font-size: 13px; }
.card-dobra[open] > summary h2::after { content: " ▴"; }
.card-dobra[open] > summary { margin-bottom: 12px; }
.dobra-numeros { font-size: 13px; color: var(--muted); }

@media (max-width: 1020px) {
  /* Numa coluna: a fila em cima e a pessoa escolhida em baixo. */
  .cand-trabalho { grid-template-columns: 1fr; }
  .cand-fila { position: static; max-height: 46vh; }
}

/* O botão do Google na página de entrada. O rótulo («Continuar com Google») é mais
   largo do que a caixa que o `.btn-outline` lhe dá ao lado do ícone e partia-se em
   três linhas. Uma linha só, com o ícone encostado ao texto. */
.btn-google {
  display: inline-flex; align-items: center; gap: 10px; white-space: nowrap;
}
.btn-google svg { width: 20px; height: 20px; flex: none; }

/* A entrada: um cartão estreito (uma coluna, como o «Account» de quem já faz isto) e o
   «ou» com um risco de cada lado, a separar o email do Google. */
/* A entrada, no desenho da indústria (Vercel/Linear/Airbnb): uma coluna estreita e
   centrada, o fornecedor à largura toda em cima, o divisor «ou» (um risco de cada
   lado), e a ação principal alinhada à direita — como o «Next» do Suno que ele mostrou.

   ⚠️ O texto dos campos fica à esquerda de propósito (`input { text-align: left }`): o
   centro é para os títulos e as ajudas, não para o que a pessoa escreve. */
.entrada-coluna { max-width: 460px; margin: 40px auto 48px; text-align: center; }
.entrada-titulo { font-size: 26px; margin: 0 0 20px; }
.entrada-cartao { max-width: 460px; padding: 26px 28px 24px; text-align: center; }
.entrada-cartao h2 { font-size: 17px; font-weight: 600; margin: 4px 0 16px; }
/* Os rótulos e as ajudas ficam à ESQUERDA, com o campo: um rótulo centrado por
   cima de um campo deixa de se ler como rótulo. O centro é do título e das perguntas. */
.entrada-cartao .vaga-acoes { justify-content: flex-end; margin-top: 16px; }
.entrada-cartao .field { margin-bottom: 12px; text-align: left; }
.entrada-abaixo { margin: 14px 0 0; font-size: 13px; }
.btn-largo { width: 100%; justify-content: center; }
.ou-divisor {
  display: flex; align-items: center; gap: 12px;
  margin: 20px 0 18px; color: var(--muted); font-size: 13px;
}
.ou-divisor::before, .ou-divisor::after {
  content: ""; flex: 1; height: 1px; background: var(--line);
}

/* A entrada em duas colunas: o painel da marca (o que a conta dá) e o cartão. Fica DENTRO da
   `.container` — nada atravessa as margens do site —, com os cantos redondos a fechar as duas
   metades. No telemóvel o painel sai de cena: o cartão é o que interessa e chega sozinho. */
.entrada-duas {
  display: grid; grid-template-columns: minmax(0, 400px) minmax(0, 1fr);
  max-width: 940px; margin: 32px auto 48px; overflow: hidden;
  border: 1px solid var(--line); border-radius: 18px; background: var(--card);
  box-shadow: var(--shadow);
}
.entrada-duas .entrada-coluna { max-width: none; margin: 0; padding: 42px 40px 40px; }
.entrada-duas .entrada-cartao { max-width: 460px; margin: 0 auto; }
.entrada-painel {
  display: flex; flex-direction: column; justify-content: center; gap: 12px;
  padding: 42px 36px; color: #fff; text-align: left;
  background: linear-gradient(158deg, var(--green-dark) 0%, var(--green) 100%);
}
.entrada-painel h2 {
  margin: 0; font-family: var(--font-display); font-size: 32px; line-height: 1.08;
  letter-spacing: -0.8px; color: #fff;
}
.entrada-painel p { margin: 0; font-size: 15.5px; line-height: 1.45; color: rgba(255, 255, 255, 0.88); }
.entrada-lista { list-style: none; margin: 20px 0 0; padding: 0; display: grid; gap: 13px; }
.entrada-lista li { display: flex; align-items: flex-start; gap: 10px; font-size: 15px; font-weight: 600; }
.entrada-lista svg { flex: none; width: 20px; height: 20px; margin-top: 1px; }
/* A entrada das empresas: a mesma casa, outro tom. O painel é escuro e o verde fica só no
   visto — é o lado institucional, não o de quem procura emprego. O botão principal do cartão
   continua verde: a acção é a mesma. */
.entrada-painel.corporativo {
  background: linear-gradient(158deg, var(--ink-950) 0%, #1c2b3a 100%);
}
.entrada-painel.corporativo .entrada-lista svg { color: var(--green); }
@media (max-width: 860px) {
  /* No telemóvel o painel desce: passa para baixo do cartão. É a ordem visual que muda (o HTML
     continua a pôr a coluna da esquerda primeiro, para o computador); quem entra quer o campo
     à frente e o discurso depois. Os cantos ficam redondos porque a grelha recorta (`overflow`). */
  .entrada-duas { grid-template-columns: minmax(0, 1fr); margin: 18px auto 32px; }
  .entrada-duas .entrada-coluna { order: 1; padding: 26px 20px 30px; }
  .entrada-painel { order: 2; padding: 24px 22px; gap: 8px; }
  .entrada-painel h2 { font-size: 24px; }
}

/* ===========================================================================
   Visão 360 das contas (gestão). Leitura densa: os números num formato que se
   compara de relance (tabular-nums), os tipos em chips, e uma tabela que rola em
   vez de partir no telemóvel.
   =========================================================================== */
.conta-numeros {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(165px, 1fr));
  gap: 12px; list-style: none; margin: 0 0 20px; padding: 0;
}
.conta-numero {
  display: flex; flex-direction: column; gap: 1px;
  padding: 14px 16px; border: 1px solid var(--line); border-radius: 12px;
}
.conta-numero-nome {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); font-weight: 600;
}
.conta-numero-valor {
  font-size: 27px; font-weight: 700; line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.conta-numero-nota { font-size: 12px; color: var(--muted); line-height: 1.35; }

.contas-scroll { overflow-x: auto; }
.contas { width: 100%; border-collapse: collapse; min-width: 860px; }
.contas th {
  text-align: left; font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); font-weight: 600; padding: 0 10px 8px; border-bottom: 1px solid var(--line);
}
.contas td { padding: 11px 10px; border-bottom: 1px solid var(--line); vertical-align: top; }
.contas tr:last-child td { border-bottom: 0; }
.contas td span { display: block; }
.contas-nome { font-weight: 600; }
.contas-pago { font-weight: 600; }
.contas-codigo { font-family: var(--mono, monospace); font-size: 13px; }
.chip {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 11.5px; font-weight: 600; border: 1px solid var(--line);
  color: var(--muted); white-space: nowrap; margin-bottom: 3px;
}
/* As cores são as da casa (--green/--gold/--paper), não invenções: verde para o que é
   empresa, dourado para o afiliado e para o que está pendente, neutro para o candidato.
   O tipo lê-se de relance sem se ler a palavra. */
.chip-empresa { background: var(--green-soft); border-color: transparent; color: var(--green-dark); }
.chip-candidato { background: var(--paper-soft); border-color: var(--line-strong); color: var(--ink-700); }
.chip-afiliado { background: var(--gold-soft); border-color: transparent; color: var(--gold-dark); }
.chip-pendente { background: var(--gold-soft); border-color: transparent; color: var(--gold-dark); font-weight: 700; }
.chip-vazio { background: transparent; color: var(--muted-light); }

@media (max-width: 700px) {
  .conta-numero-valor { font-size: 22px; }
}

/* A ficha 360 de uma conta: cartões numa grelha que aperta sozinha, e linhas com o
   rótulo à esquerda e o valor à direita (lê-se em coluna, como uma ficha). */
.ficha-grelha {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 16px; align-items: start;
}
.admin-head-numeros { display: flex; gap: 18px; flex-wrap: wrap; }
.admin-head-numeros span { font-size: 14px; color: var(--muted); }
.admin-head-numeros strong { font-size: 19px; color: inherit; font-variant-numeric: tabular-nums; }
.ficha-linha { display: flex; justify-content: space-between; gap: 14px; align-items: baseline; }
.ficha-linha > span:last-child { text-align: right; }

/* A foto do perfil: é o MESMO widget do editor do CV (`#photo-card`, em app.js), com a caixa
   redonda em vez do quadrado — e vive onde o CV o põe: na primeira coluna da grelha dos campos
   (`.dados-grid`, cuja primeira linha é [Foto][campo][campo]). Tocar no círculo abre o seletor e,
   a seguir, o recorte. A câmara diz que ele é um botão (no telemóvel não há `hover`, por isso está
   sempre à vista) e o × remove — os dois no canto, como o CV faz na miniatura. Os 120px são o
   número que a casa já tinha para a foto do perfil (`.photo-preview`), não uma medida nova. */
#photo-card.avatar-foto { position: relative; }
#photo-card.avatar-foto .photo-pick {
  position: relative; display: block; width: 100%; max-width: 120px; height: 120px;
  /* O quadrado com número, não com `aspect-ratio`: este widget é o MESMO do editor do CV
     (`#photo-card`) e traz de lá a altura — medido, a foto saía 120×146 (um oval) e nem
     `aspect-ratio` nem `align-self` nem `min-height: 0` a convenceram. `height: 120px` é o
     número que a casa já tinha para a foto do perfil; o `max-width: 100%` trata do estreito. */
  max-height: 120px; align-self: flex-start;
  padding: 0; margin: 0; border: 0; border-radius: 50%; background: none; overflow: hidden;
}
/* Vazio (sem foto carregada e sem foto da conta Google) quem é o botão é o próprio círculo:
   tracejado, como o quadrado do CV. Com uma cara lá dentro, moldura nenhuma. */
#photo-card.avatar-foto.vazio .photo-pick {
  border: 1.5px dashed var(--line-strong); background: var(--paper-soft);
}
#photo-card.avatar-foto.vazio .photo-pick:hover,
#photo-card.avatar-foto.vazio .photo-pick:focus-visible {
  border-color: var(--green); background: var(--green-soft);
}
#photo-card.avatar-foto .photo-preview { width: 100%; height: 100%; border-radius: 50%; border: 0; }
#photo-card.avatar-foto .photo-pick .avatar,
#photo-card.avatar-foto .photo-pick .avatar-fallback { width: 100%; height: 100%; font-size: 44px; }
#photo-card.avatar-foto .avatar-edit {
  position: absolute; right: -4px; bottom: -4px; z-index: 2;
  display: flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--green); color: #fff; border: 2px solid var(--card);
  transition: background 0.15s ease;
}
#photo-card.avatar-foto .avatar-edit svg { width: 12px; height: 12px; }
#photo-card.avatar-foto .photo-pick:hover .avatar-edit,
#photo-card.avatar-foto .photo-pick:focus-visible .avatar-edit { background: var(--green-dark); }
#photo-card.avatar-foto .photo-x { top: -4px; right: -4px; }
#photo-card.avatar-foto .photo-pick:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }
/* O estado fica por baixo do círculo, centrado com ele. O `margin-left` de 10px do CV não faz
   sentido aqui (lá vive na fila dos controlos do recorte). */
#photo-card.avatar-foto #photo-status { margin-left: 0; min-height: 14px; text-align: center; }

/* ------------------------------------------------------------- painel: o cabeçalho e a tira

   O painel tinha duas listas e nenhuma hierarquia: quem entrava não via o que tinha nem o que
   fazer. Estas regras dão-lhe o que falta — o nome em display (o mesmo `Sora` da marca), uma só
   linha de estado por baixo (e nenhuma quando não há nada a dizer), e o botão primário à direita.
   Em ecrã estreito o botão desce e ocupa a largura: um botão primário de 90px num telemóvel é um
   alvo que se falha. */

.dash-hello {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 18px; flex-wrap: wrap; margin: 26px 0 22px;
}
.dash-hello-texto { min-width: 0; }
.dash-hello-acoes { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* O «+ Criar CV» é UMA peça centrada no botão: o ícone e o rótulo viajam juntos na fila, e o grupo
   é que se centra (é ele que tem de estar no meio, não a palavra sozinha). */
.dash-hello-acoes .btn.btn-com-ico { display: inline-flex; align-items: center; gap: 8px; }
.dash-hello-acoes .btn-ico {
  width: 16px; height: 16px; flex: 0 0 auto;
  /* O símbolo `i-mais` da casa é um `<path>` só com `d` — sem `stroke` e sem `fill:none`. Num svg
     sem estas regras, um traço sem área, preenchido a preto, não se vê: o «+» estava lá, invisível. */
  fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round;
}
.dash-hello h1 {
  font-weight: 700; line-height: 1.08; margin: 0;
}
/* A descrição da cabeça. `.dash-passo` é a do painel do candidato (a régua: 7px abaixo do
   título); as outras nasceram com o `p.muted` do sítio — 15,5px de folga e de letra. */
.dash-passo,
.admin-head .muted,
.order-head .muted,
.cat-head .muted { margin: 7px 0 0; color: var(--muted); font-size: 15px; line-height: 1.45; }
.dash-hello-acoes .btn { padding-left: 16px; padding-right: 16px; }
@media (max-width: 640px) {
  .dash-hello { align-items: stretch; }
  .dash-hello-acoes { width: 100%; justify-content: flex-end; }
  .dash-hello h1 { font-size: 22px; }
  .dash-hello-acoes .btn { flex: 0 1 auto; }   /* largura do PRÓPRIO texto: um botão que cresce
                                                       só para encher a linha é um bar com rótulo */   /* em telemóvel ficam lado a lado, cada um
                                                        com a largura do seu texto (cabem) */
}

/* A tira dos números como navegação: mesma `.num` da casa, com o alvo a reagir ao rato. */
.nums-nav .num { text-decoration: none; color: inherit; transition: border-color .15s ease, transform .15s ease; }
.nums-nav .num:hover { border-color: var(--green); transform: translateY(-1px); }
.nums-nav .num.is-vivo b { color: var(--green); }
.nums-nav .num.is-alerta { border-color: var(--green); }
.nums-nav .num.is-alerta b { color: var(--green-dark); }
@media (max-width: 760px) { .nums-nav { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* A lista de candidaturas (a página das candidaturas, `/candidato/candidaturas/`): uma ficha por
   linha, com o título, a empresa e o selo do estado. (O painel já não desenha nada disto — saiu em
   Out/2026; as regras da linha do painel foram-se com ele, e com elas a trilha em barras, que só
   o painel tinha. O `CandidaturaVaga.trilha` ficou: é dado, e volta a ter ecrã no dia em que a
   página das candidaturas a mostrar.) */
.cand-lista { display: grid; gap: 10px; }
.cand {
  display: block; padding: 13px 15px; border: 1px solid var(--line); border-radius: 14px;
  background: var(--card); text-decoration: none; color: inherit;
  transition: border-color .15s ease;
}
.cand:hover { border-color: var(--green); }

.cand-vazio { padding: 4px 0 2px; }
.cand-vazio p { margin: 0 0 12px; }

/* O aviso do dinheiro: número, frase e ação no mesmo cartão. Âmbar, não vermelho — não é um erro,
   é uma coisa por acabar — e o botão é escuro para não competir com o verde do «Criar novo CV». */
.aviso-pagar {
  display: flex; align-items: center; gap: 12px; flex-wrap: nowrap;
  background: #fdf6e3; border: 1px solid #f0e2bd; border-radius: 14px;
  padding: 13px 16px; margin: 0;
}
/* Em ecrã estreito (o bloco passa a ocupar a linha toda) o botão volta a poder descer. */
@media (max-width: 900px) { .aviso-pagar { flex-wrap: wrap; } }
.aviso-pagar-ico { width: 22px; height: 22px; color: #8a5a00; flex: 0 0 auto; }
/* O botão do aviso não parte o texto: «Ver por pagar» em duas linhas parecia um botão avariado. */
.aviso-pagar .btn { white-space: nowrap; }
.aviso-pagar-num {
  font-family: var(--font-display); font-size: 30px; font-weight: 800; line-height: 1;
  color: #8a5a00; flex: 0 0 auto;
}
.aviso-pagar-txt { flex: 1 1 auto; min-width: 0; }
.aviso-pagar-txt b { display: block; color: #8a5a00; font-size: 15px; }
.aviso-pagar-txt span { display: block; margin-top: 2px; color: #7a6a45; font-size: 13.5px; }
@media (max-width: 560px) { .aviso-pagar .btn { width: 100%; text-align: center; } }

/* O interior dos cartões dos números, como na foto dele: o ícone à ESQUERDA, dentro de um quadrado
   verde claro, e o número com a palavra à direita.

   ⚠️ Os seletores levam `.nums-nav .num` à frente de propósito. A casa tem `.num span { display:
   block; ... }` (especificidade 0,1,1) e um `.num-ico` sozinho (0,1,0) PERDIA — o quadrado nunca
   era um flex e o ícone ficava encostado ao canto (medido: chip e svg ambos em x=229, y=217.5, com
   o glifo a 0px do canto). Com a mesma especificidade e as regras no fim do ficheiro, ganha esta. */
.nums-nav .num { display: flex; align-items: center; gap: 10px; padding: 12px 14px; }
.nums-nav .num .num-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: 9px; margin: 0;
  background: var(--green-soft); color: var(--green-dark); flex: 0 0 auto;
}
.nums-nav .num .num-ico svg { display: block; width: 17px; height: 17px; }
.nums-nav .num .num-txt { display: flex; flex-direction: column; min-width: 0; margin: 0; }
.nums-nav .num .num-txt b {
  display: block; font-size: 24px; font-weight: 800; line-height: 1.05; color: var(--ink-900);
}
.nums-nav .num .num-txt span {
  display: block; margin-top: 1px; color: var(--muted); font-size: 13px;
}
/* A tira tem três cartões de números e — quando há o que pagar — o bloco amarelo como QUARTA
   coluna, mais larga (é o único que tem uma frase e um botão). Sem pagamento, ficam três colunas
   iguais, sem vazio nenhum. */
.nums-nav { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.nums-nav:has(.aviso-pagar) { grid-template-columns: repeat(3, minmax(0, 1fr)) minmax(0, 1.6fr); }
@media (max-width: 900px) {
  .nums-nav:has(.aviso-pagar) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .nums-nav:has(.aviso-pagar) .aviso-pagar { grid-column: 1 / -1; }
}
@media (max-width: 760px) { .nums-nav { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ---------------------------------------------------------- a vaga a que já se candidatou

   O cartão ganha uma marca discreta (o rebordo esquerdo verde) e o selo do estado na coluna da
   direita, por cima da nota das datas. Não é um cartão novo: é o MESMO cartão a dizer mais uma
   coisa — quem já enviou reconhece a vaga de longe, sem ler. */

.vaga-cartao.is-candidatada { border-left: 3px solid var(--green); }
.vaga-cartao-selo { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.vaga-selo-frase { color: var(--green-dark); font-size: 12.5px; font-weight: 600; }
@media (max-width: 640px) {
  .vaga-cartao-selo { flex-direction: row; align-items: center; justify-content: space-between; width: 100%; }
}



/* O primeiro cartão da tira com a cor cheia: o painel tem de ter um sítio para onde apontar, e o
   que precisa de olhos são as vagas. Vem depois da `.nums-nav .num` (empate de especificidade:
   ganha a última). */
.nums-nav .num--destaque { background: var(--green); border-color: var(--green); }
.nums-nav .num--destaque .num-ico { background: rgba(255, 255, 255, .18); color: #fff; }
.nums-nav .num--destaque .num-txt b,
.nums-nav .num--destaque .num-txt span { color: #fff; }


/* Quatro cartões, quatro colunas: a grelha da casa é de três (o aviso do pagamento ocupava a
   quarta), e com quatro cartões o último caía para uma segunda fila. Preso a `.nums-nav` porque o
   `.nums` também serve o painel das empresas. */

/* O traço dos ícones do quadrado: o símbolo `i-bag` do sprite não traz `stroke` nem `fill:none`,
   por isso saía preenchido a preto. Quem já traz o seu traço não se queixa desta regra. */
.nums-nav .num-ico svg { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }


/* ── A casca da área do candidato ────────────────────────────────────────────────────────────
   Computador: o menu vai para a esquerda, preso (fica enquanto se rola) e o cabeçalho do site sai
   — a marca muda-se para o cimo do menu. Telemóvel: o cabeçalho fica e entra a barra de baixo, com
   o «+» verde a meio. A marcação das duas cascas vive no HTML (é o CSS que escolhe qual se vê),
   para os testes de barra continuarem a medir o que mediam. */
.app-lado, .app-baixo { display: none; }

@media (min-width: 901px) {
  .app-area .site-header { display: none; }
  .app-area .app-lado {
    display: flex; flex-direction: column;
    position: fixed; top: 0; bottom: 0; left: 0; width: 232px; z-index: 40;
    background: var(--card); border-right: 1px solid var(--line);
    padding: 18px 14px;
  }
  .app-lado-marca { display: block; padding: 2px 8px 16px; }
  .app-lado-marca img { display: block; height: 26px; width: auto; }
  .app-lado-menu { display: flex; flex-direction: column; gap: 2px; }
  .app-item {
    display: flex; align-items: center; gap: 10px;
    padding: 10px; border-radius: 10px; text-decoration: none;
    color: var(--ink-700); font-weight: 500;
  }
  .app-item .vi { width: 17px; height: 17px; flex: 0 0 auto; }
  .app-item:hover { background: var(--paper-soft); }
  .app-item.is-active { background: var(--green-soft); color: var(--green-dark); font-weight: 600; }
  .app-lado-pe {
    margin-top: auto; padding-top: 12px; border-top: 1px solid var(--line);
    display: flex; flex-direction: column; gap: 2px;
  }
  .app-lado-nome { padding: 2px 10px 8px; font-weight: 600; color: var(--ink-900); }
  .app-lado-lig { padding: 7px 10px; border-radius: 8px; text-decoration: none; color: var(--muted); }
  .app-lado-lig:hover { background: var(--paper-soft); color: var(--ink-900); }
  /* O conteúdo sai de baixo do menu — e o RODAPÉ também. O `.site-footer` vive FORA do `main`
     (tem o seu próprio `.container`), por isso não herdava o desvio: o «FonteCV» do rodapé, que é a
     coluna da esquerda, ficava debaixo do menu com o nome cortado a meio («nteCV» à vista). */
  .app-area main.container,
  .app-area .site-footer .container { margin-left: 232px; margin-right: auto; }
  /* Quatro cartões na tira são coisa de computador: no telemóvel a grelha da casa é de 2 e fica o
     2×2 do desenho. Sem isto, a regra ganhava em todo o lado e o texto cortava-se («16 Vac…»). */
  
}

@media (max-width: 900px) {
  /* No Android, um elemento mais largo que o ecrã faz o browser alargar a
     página: os `position: fixed` (o «+») passam a ser posicionados contra essa
     largura e ficam meio fora do ecrã. A barra de estilos já tem o seu próprio
     scroll; a página não precisa de rolar para o lado. */
  .app-area { overflow-x: clip; }
  /* O botão preto do editor é `sticky` a 12px do fundo — ficava debaixo da
     barra fixa. Sobe o que a barra ocupa. */
  .app-area .sticky-actions { bottom: calc(84px + env(safe-area-inset-bottom)); }
  .app-area .app-baixo {
    display: flex; align-items: center;
    position: fixed; bottom: 0; left: 0; right: 0; z-index: 40;
    background: var(--card); border-top: 1px solid var(--line);
    padding: 6px 6px calc(6px + env(safe-area-inset-bottom));
  }
  /* Os dois lados crescem por igual: com «Vagas»/«Candidaturas» escondidos, o «+»
     ficava encostado a uma das pontas. Assim fica sempre ao meio. */
  .app-baixo-lado { display: flex; align-items: center; flex: 1 1 0; min-width: 0; }
  /* Sem nada do lado direito (nem candidaturas nem o «+»), os itens da esquerda
     repartem a barra toda em vez de ficarem encostados à metade esquerda. */
  .app-baixo:not(:has(.app-baixo-lado:last-of-type .app-baixo-item)) .app-baixo-lado:first-of-type {
    flex: 1 1 100%;
    justify-content: space-around;
  }
  .app-baixo-item {
    flex: 1 1 0; display: flex; flex-direction: column; align-items: center; gap: 3px;
    padding: 4px 2px; border-radius: 10px; text-decoration: none;
    color: var(--muted); font-size: 11px;
  }
  .app-baixo-item .vi { width: 21px; height: 21px; }
  .app-baixo-item.is-active { color: var(--green-dark); font-weight: 600; }
  .app-baixo-mais {
    flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
    width: 46px; height: 46px; margin: 0 4px; border-radius: 50%;
    background: var(--green); color: #fff; box-shadow: 0 6px 16px rgba(14, 138, 94, .35);
  }
  .app-baixo-mais .vi { width: 24px; height: 24px; }
  /* O «+» do candidato é um <details> (a folha com Novo CV / Nova carta) e o das empresas um link:
     o invólucro existe para o botão ficar exactamente onde estava. */
  .app-baixo-mais-wrap { flex: 0 0 auto; }
  .app-baixo-mais-wrap > summary { list-style: none; cursor: pointer; }
  .app-baixo-mais-wrap > summary::-webkit-details-marker { display: none; }
  .app-baixo-mais-wrap > summary::marker { content: ""; }
  /* A folha sobe por cima da barra, ao centro, alinhada com o botão que a abre. */
  .app-mais-lista {
    position: fixed; bottom: calc(76px + env(safe-area-inset-bottom)); left: 50%;
    transform: translateX(-50%); z-index: 41;
    display: flex; flex-direction: column; min-width: 212px; padding: 6px;
    background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-sm);
    box-shadow: 0 12px 30px rgba(16, 24, 40, .18);
  }
  .app-mais-lista a {
    display: flex; align-items: center; gap: 10px; padding: 11px 12px;
    color: var(--ink-900); font-size: 14px; font-weight: 600; text-decoration: none;
    border-radius: 8px;
  }
  .app-mais-lista a:active { background: #f2f4f7; }
  .app-mais-lista .vi { width: 19px; height: 19px; color: var(--green-dark); flex: none; }
  /* O fim da página não pode ficar debaixo da barra. */
  .app-area { padding-bottom: 76px; }
}

/* A tira dos números: quatro cartões no computador (as vagas, candidaturas, CVs e cartas), dois no
   telemóvel — o 2×2 do desenho. Presa a `.nums-nav` porque o `.nums` também serve o painel das
   empresas. Específica (0,2,0) de propósito: tem de ganhar à regra dos três cartões da casa. */
@media (min-width: 901px) { .nums.nums-nav { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 900px) { .nums.nums-nav { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* (Aqui viviam as regras das vagas do painel — `.dash-vagas` e os `.vaga-carta-*` —, todas
   exclusivas da secção «Vagas novas para ti», que saiu do painel em Out/2026. As vagas da página
   pública e das empresas usam `.vaga-cartao`, que é outro cartão e não se lhe toca.) */


/* Dentro da área, no telemóvel, o botão do cabeçalho é a CONTA: o «Eu» sobe da barra de baixo para
   aqui (o hambúrguer é do site, e dentro da área não tem nada que abrir). Fora da área o «Eu» não
   existe — o `.nav-eu` nasce escondido. A barra de baixo fica com os destinos partidos em dois
   grupos de largura IGUAL, um de cada lado do «+»: é isso que põe o «+» ao meio por construção
   (com o «+» em terceiro de quatro dava 55px de desvio a 390px). */
.nav-eu { display: none; }

@media (max-width: 760px) {
  /* Peso 0,3,1: a regra que mostra o hambúrguer em mobile é `.header-inner.mobile-hamburguer .nav-toggle`
     (0,3,0) — uma `.app-area .nav-toggle` (0,2,0) perdia e o botão ficava lá. */
  body.app-area .header-inner .nav-toggle { display: none; }
  /* O «Eu» abre um menu: é um <details>, logo abre sem JavaScript. O look mora no <summary>
     (o <details> é só a caixa que segura a lista) e a lista cresce para a ESQUERDA (`right: 0`)
     porque o «Eu» está no canto direito — nada pode passar o limite à direita. */
  .app-area .nav-eu { position: relative; display: inline-block; }
  .app-area .nav-eu > summary { display: inline-flex; align-items: center; gap: 6px; padding: 7px 11px; border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--ink-900); font-size: 12.5px; font-weight: 600; list-style: none; cursor: pointer; }
  .app-area .nav-eu > summary::-webkit-details-marker { display: none; }
  .app-area .nav-eu > summary::marker { content: ""; }
  .app-area .nav-eu[open] > summary { border-color: var(--green-dark); color: var(--green-dark); }
  .app-area .nav-eu-lista { position: absolute; top: calc(100% + 6px); right: 0; z-index: 40; min-width: 186px; padding: 6px; display: flex; flex-direction: column; background: #fff; border: 1px solid var(--line); border-radius: var(--radius-sm); box-shadow: 0 10px 26px rgba(16, 24, 40, .16); }
  .app-area .nav-eu-lista a { display: flex; align-items: center; gap: 9px; padding: 9px 10px; border-radius: 8px; color: var(--ink-900); font-size: 13.5px; text-decoration: none; }
  .app-area .nav-eu-lista a .vi { width: 17px; height: 17px; color: var(--muted); flex: none; }
  .app-area .nav-eu-lista a:active .vi { color: var(--green-dark); }
  .app-area .nav-eu-lista a:active { background: #f2f4f7; }
  .app-area .nav-eu .vi { width: 18px; height: 18px; }
}

/* Os grupos da barra de baixo vivem na MESMA media query que abre a barra
   (`.app-area .app-baixo`, @media max-width 900px): aos 844px a barra já aparecia e os grupos
   ainda não, e o «+» saía a 353px do centro. Aqui vai junto com ela. */
@media (max-width: 900px) {
  .app-baixo-lado { display: flex; flex: 1 1 0; min-width: 0; }
  .app-baixo-lado .app-baixo-item { flex: 1 1 0; }
}


/* ------------------------------------------------------------------ o recibo
   `/candidato/pagamentos/<pk>/recibo/`: a folha que se imprime. Em papel sai só o recibo — a barra
   lateral, o cabeçalho e a barra de baixo são do site, e quem imprime quer o papel. */
.recibo {
  max-width: 720px;
  background: #fff;
  border: 1px solid #e6e8ec;
  border-radius: 12px;
  padding: 26px 30px;
}
.recibo-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}
.recibo-num {
  font-family: "Sora", system-ui, sans-serif;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.3px;
}
.recibo-sub { color: #6b7280; font-size: 13px; margin-top: 2px; }
.recibo-linhas { width: 100%; border-collapse: collapse; }
.recibo-linhas th,
.recibo-linhas td {
  text-align: left;
  padding: 10px 0;
  border-bottom: 1px solid #eef0f3;
  font-weight: 400;
  vertical-align: top;
}
.recibo-linhas th { color: #6b7280; font-size: 13px; width: 38%; }
.recibo-linhas td:last-child { text-align: right; }
.recibo-total { font-size: 18px; font-weight: 700; }
.recibo-nota { margin-top: 16px; }
.pay-valor { font-variant-numeric: tabular-nums; }

@media print {
  .app-lado,
  .site-header,
  .app-baixo,
  .no-print { display: none !important; }
  main.container { padding: 0; }
  .recibo { border: 0; padding: 0; max-width: none; }
  body { background: #fff; }
}


/* ------------------------------------------------------------------ o menu da gestão
   `/gestao_interna/`: três portas à vista e o índice completo no ☰ — ele, «nao precisam ter mais do
   que 3 visiveis... empurra tudo no hamburguer». No computador o painel abre em duas colunas; no
   telemóvel, onde a barra inteira já vive dentro do painel do cabeçalho, a lista abre em LINHA: dois
   painéis encaixados davam dois `scroll`s e um ☰ que parecia morto. */
.head-menu-gestao > button { display: inline-flex; align-items: center; gap: 6px; }
.head-menu-gestao > button svg { width: 18px; height: 18px; }
.head-menu-gestao-lista {
  min-width: 250px;
  max-height: min(74vh, 620px);
  overflow-y: auto;
}
.menu-grupo { display: block; padding: 3px 0; }
.menu-grupo + .menu-grupo { border-top: 1px solid #eef0f3; }
.menu-titulo {
  display: block;
  padding: 7px 12px 2px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: #98a2b3;
}
@media (min-width: 900px) {
  .head-menu-gestao-lista { width: 560px; columns: 2; column-gap: 22px; }
  .menu-grupo { break-inside: avoid; }
  .menu-grupo + .menu-grupo { border-top: 0; }
}
.header-inner.nav-collapsed .site-nav.open .head-menu-gestao > button { display: none; }
.header-inner.nav-collapsed .site-nav.open[data-menu="lista"] > a.link { display: none; }
.header-inner.nav-collapsed .site-nav.open .head-menu-gestao-lista {
  position: static;
  display: block;
  min-width: 0;
  width: auto;
  max-height: none;
  overflow: visible;
  columns: 1;
  padding: 0;
  border: 0;
  box-shadow: none;
}

/* «Importar de um CV antigo» diz o que faz, e que é a IA que o faz (Out/2026):
   o botão passou a ter duas linhas — a acção e uma dica de uma linha — e um
   selo «IA». A dica existe porque o botão sozinho não dizia que o importador
   lê o ficheiro, aponta o que está mal e preenche; quem nunca importou não
   tinha como adivinhar. As duas linhas ficam DENTRO do botão para não haver
   um texto solto ao lado a competir com o nome do documento. */
.btn-import {
  align-items: flex-start;
  text-align: left;
  padding-top: 7px;
  padding-bottom: 7px;
  line-height: 1.25;
}
.btn-import > svg {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  margin-top: 1px;
}
.imp-btn-txt {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.imp-btn-linha {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}
.ia-tag {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 1px 6px 1px 4px;
  border-radius: 999px;
  background: rgba(14, 138, 94, 0.12);
  color: #0e8a5e;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  line-height: 1.5;
}
.ia-tag svg { width: 11px; height: 11px; }
.imp-btn-dica {
  font-size: 11.5px;
  font-weight: 500;
  opacity: 0.72;
  white-space: normal;
  max-width: 320px;
}
@media (max-width: 560px) {
  .imp-btn-dica { max-width: 100%; }
}

/* A oferta de preparar o CV para ESTA vaga, dentro do cartão da vaga.
   Não é um botão solto ao lado da candidatura: é o degrau que falta a quem
   ainda não tem CV pronto, e por isso vem com o preço à vista e a alternativa
   da carta. O preço vem do catálogo (contexto `preco_cv`), não do template. */
.vaga-preparar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}
.vaga-preparar-lig {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 16px;
  margin-top: 12px;
  font-size: 14px;
}
.vaga-preparar-lig a { color: var(--green-700, #0e8a5e); font-weight: 600; }

/* O selo das vagas recolhidas de outro portal: diz de onde vêm antes de a pessoa
   clicar, para não pensar que a candidatura se faz aqui. */
.vaga-de-fora {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--paper);
  border: 1px solid var(--line);
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  vertical-align: 1px;
}

/* A tabela das vagas de fora: o resumo pode ser comprido e empurrava a coluna
   «Decidir» para fora do cartão (os botões ficavam cortados à direita). Com
   largura fixa e quebra de texto, as quatro colunas cabem. */
/* `table[data-cards] td` (atributo + elemento) ganha a `.gestao-vagas td`; o
   seletor tem de ter a mesma força, senão o `white-space: nowrap` da tabela
   genérica ficava e o título passava por cima do resumo. */
table[data-cards].gestao-vagas { table-layout: fixed; width: 100%; }
table[data-cards].gestao-vagas th,
table[data-cards].gestao-vagas td {
  white-space: normal;
  overflow-wrap: anywhere;
  vertical-align: top;
}
table[data-cards].gestao-vagas th:nth-child(1),
table[data-cards].gestao-vagas td:nth-child(1) { width: 27%; }
table[data-cards].gestao-vagas th:nth-child(2),
table[data-cards].gestao-vagas td:nth-child(2) { width: 37%; }
table[data-cards].gestao-vagas th:nth-child(3),
table[data-cards].gestao-vagas td:nth-child(3) { width: 12%; }
table[data-cards].gestao-vagas th:nth-child(4),
table[data-cards].gestao-vagas td:nth-child(4) { width: 24%; }
table[data-cards].gestao-vagas td:nth-child(4) form { display: flex; gap: 6px; flex-wrap: wrap; }

/* O resumo de uma vaga de fora: é texto para ler, não um rótulo de interface.
   Fica maior do que o corpo normal porque é a única coisa que a pessoa tem
   para decidir se vale a pena abrir o anúncio. */
.vaga-resumo {
  font-size: 17px;
  line-height: 1.65;
  max-width: 68ch;
}
.vaga-botoes {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 14px 0 10px;
}

/* O apelo de quem foi bloqueado: uma coluna estreita, porque é uma página de uma
   frase só — ler, escrever, enviar. Ao lado de um formulário largo, o pedido de
   alguém bloqueado parecia um formulário de registo. */
.conta-bloqueada {
  max-width: 620px;
  margin: 40px auto;
}
.conta-bloqueada h1 { margin-bottom: 6px; }
.conta-bloqueada form { margin-top: 18px; }
.form-erro {
  background: #fdecec;
  border: 1px solid #f3c2c2;
  color: #8a1f1f;
  border-radius: 10px;
  padding: 10px 12px;
  font-size: 14.5px;
  margin: 10px 0;
}

/* A fila dos apelos: o texto da pessoa é o que se lê primeiro, e tem de quebrar
   dentro da coluna — uma frase longa sem espaços não pode empurrar os botões. */
.apelo-texto { white-space: normal; overflow-wrap: anywhere; max-width: 46ch; }
.apelo-acoes form { display: flex; flex-wrap: wrap; gap: 8px; }
.sep { border: 0; border-top: 1px solid var(--line); margin: 26px 0 18px; }

/* A fila dos apelos é uma tabela de COLUNAS FIXAS: sem isto, a frase de quem escreveu
   esticava a coluna e empurrava os botões para fora do cartão (medido: os botões
   apareciam por cima do texto). `white-space: normal` ganha ao `nowrap` do
   `table[data-cards]` por especificidade — os dois seleccionadores têm o mesmo peso
   que a regra genérica, e esta vem depois. */
table.apelos[data-cards] { table-layout: fixed; width: 100%; }
table.apelos[data-cards] th,
table.apelos[data-cards] td {
  white-space: normal;
  overflow-wrap: anywhere;
  vertical-align: top;
}
table.apelos[data-cards] th:nth-child(1),
table.apelos[data-cards] td:nth-child(1) { width: 26%; }
table.apelos[data-cards] th:nth-child(2),
table.apelos[data-cards] td:nth-child(2) { width: 48%; }
table.apelos[data-cards] th:nth-child(3),
table.apelos[data-cards] td:nth-child(3) { width: 26%; }

/* O «Entrar» do telemóvel: a barra do sítio está escondida abaixo dos 760px e o botão
   que lá vive não se vê. Este é o mesmo link, fora da barra, só nesse tamanho. */
.btn-entrar-mob { display: none; }
@media (max-width: 760px) {
  .btn-entrar-mob { display: inline-flex; }
  /* O da casca dá lugar a este: dois «Entrar» lado a lado foi o que se viu na
     primeira montagem. */
  .btn-entrar-casca { display: none; }
}

/* O download no fim: depois dos detalhes, tracejado, a dizer quando abre. */
.pedido-descarregar {
  display: flex; flex-direction: column; align-items: stretch; gap: 6px;
  margin-top: 14px;
}
.pedido-descarregar .btn, .pedido-descarregar .is-disabled { width: 100%; justify-content: center; }
.pedido-descarregar .pagar-nota { text-align: center; margin: 0; }

/* Sem métodos disponíveis o valor não pode desaparecer: fica uma linha sóbria
   antes do aviso, em vez de reaparecer a antiga caixa do total. */
.price-only {
  margin: 4px 0 10px;
  font-size: 14px;
  color: var(--muted);
}
.price-only strong { color: var(--ink); font-variant-numeric: tabular-nums; }

/* O dólar por baixo do Kz, na faixa dos estilos: pequeno e discreto — é a
   mesma quantia noutra moeda, não um segundo preço. */
.style-price-usd {
  display: block;
  margin-top: 1px;
  font-size: 11px;
  font-weight: 500;
  color: var(--muted);
  letter-spacing: 0.01em;
}

/* O dólar por baixo do Kz nos cartões dos modelos: é a mesma quantia noutra
   moeda, para quem vem de fora não ter de fazer a conta. */
.prod-price-usd {
  display: block;
  margin-top: 1px;
  font-size: 11px;
  font-weight: 500;
  color: var(--muted);
  letter-spacing: 0.01em;
}

/* O dólar ao lado do «desde», na secção do preço: mesma quantia, outra moeda. */
.lp-valor-usd {
  display: block;
  margin-top: 2px;
  font-family: var(--font-body);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--muted);
}

/* Cobertura de campos na página «Campos dos CVs»: a barra dá a forma, o número
   ao lado dá o valor. 90px chega para comparar duas linhas sem virar gráfico. */
.barra-mini {
  display: inline-block; width: 90px; height: 4px; margin-right: 8px;
  border-radius: 999px; background: rgba(12, 30, 22, 0.09);
  vertical-align: middle; overflow: hidden;
}
.barra-mini > span { display: block; height: 100%; border-radius: 999px; background: var(--green); }

/* No telemóvel o leque encolhe e as etiquetas entram para dentro da folha: os
   desvios negativos do desktop, a 390px, davam barra horizontal — o mesmo
   defeito do `<input type=file>` de Out/2026, por outra porta. */
@media (max-width: 760px) {
  /* O leque tem de caber nos ~350px da coluna: 260px de folha, 8% de desvio e
     5° de rotação somam 316px. Com os 330px de antes, o leque saía da coluna e
     era CORTADO pela borda (não dava barra, porque o `body` esconde o excesso —
     o corte silencioso é pior do que a barra). */
  .lp-hero-shot { max-width: 260px; margin: 8px auto 0; }
  .lp-sheet-esq { transform: translate(-8%, -3%) rotate(-5deg) scale(0.92); }
  .lp-sheet-dir { transform: translate(8%, -2%) rotate(5deg) scale(0.92); }
}
/* No telemóvel as etiquetas saem: o hero já diz «escolhe o modelo, preenche e
   recebe o PDF» na linha de cima, e a 390px elas tapavam o nome do CV. */
@media (max-width: 640px) {
  .lp-chip { display: none; }
}
