/* ------------------------------------------------------------------
   daponto - ZONA DO UTILIZADOR (a porta, o cartão, os vouchers, a conta).
   Folha da MAQUETA. Companheira do site.css, nunca substituta dele:
   as cores, a forma, as fontes e os botões vêm todos de lá.

   ⚠️ A REGRA DE OURO DO PADDING é a do site.css e vale aqui na mesma:
   qualquer elemento que TAMBÉM tenha .wrap usa padding-block, nunca o
   atalho `padding: Npx 0`. Nesta folha isso apanha: .auth-in, .me-in,
   .vd-in e .set-in.

   ------------------------------------------------------------------
   O QUE ESTA ZONA TEM DE DIFERENTE DA MONTRA, E PORQUÊ

   1. `noindex,nofollow` em TODAS estas páginas, e `Cache-Control:
      private, no-store` no servidor. A montra existe para ser
      indexada; isto existe para não ser. São páginas com nome, saldo e
      vouchers de uma pessoa: um intermediário que as guarde serve-as à
      pessoa seguinte.
   2. O cabeçalho muda: sai o botão «Entrar» e entram o saldo e o menu
      do utilizador. Nada mais muda: a barra de categorias e o rodapé
      são os mesmos, porque quem tem sessão continua a ser um visitante
      da montra.
   3. Duas páginas, não três. Na APP o Cartão e os Vouchers são
      separadores porque o telemóvel tem barra em baixo e ela obriga a
      dividir. Aqui não há barra nenhuma, e as duas respondem à mesma
      pergunta - «o que é que eu tenho?» -, por isso vivem juntas. As
      Definições ficam à parte, que é outra pergunta.
   ------------------------------------------------------------------ */


/* ==================================================================
   CABEÇALHO COM SESSÃO
   ================================================================== */

/* O saldo é um LINK para o cartão, não um enfeite: quem olha para os
   pontos quer saber o que faz com eles. */
.pts-pill{
    display:inline-flex; align-items:center; gap:8px; height:40px; padding:0 15px;
    border-radius:var(--r-pill); background:var(--brand-soft); color:var(--brand-ink);
    font-family:var(--f-head); font-size:14px; white-space:nowrap;
}
.pts-pill i{ font-size:13px }
.pts-pill:hover{ background:#DCF0F9 }


/* ⚠️ O `.av` (a bolha de iniciais) MUDOU-SE PARA O `site.css` a 2026-09-07, quando
   passou a ser desenhado no cabecalho de todas as paginas. Nao esta duplicado: esta la,
   e so la. As variantes que dependem do contexto desta folha (`.pp-row .av`,
   `.vrow .av`) continuam aqui em baixo, coladas aos blocos delas. */

/* ⚠️ O MENU DO UTILIZADOR (`.me`, `.me-btn`, `.me-menu`) mudou-se para o `site.css`
   a 2026-09-07, pela mesma razao do `.av`: e desenhado no cabecalho de TODAS as
   paginas, e nenhuma da montra carrega esta folha. */


/* ==================================================================
   A PORTA (entrar)

   UMA porta só, e é a verdade do sistema: o REQUEST_PIN_MODULE cria o
   `user_id` dentro do token e o SIGNIN_MODULE faz o INSERT quando o PIN
   acerta. Não existe «criar conta» em lado nenhum, logo não se desenha
   um segundo botão a prometer um caminho que não há.
   ================================================================== */

.auth-in{ padding-block:64px 90px; display:flex; justify-content:center }
.auth{ width:100%; max-width:430px }

/* COM CARTAO, e o MESMO das Definicoes (regra do Peter, 2026-08-30).
   Cheguei a tirar-lho por causa do degrade que estava no perfil, e
   confundi duas coisas: o que ali estava a mais era a COR de
   enchimento, nao a moldura. A moldura fica, e fica igual a das
   Definicoes - contorno de um pixel, canto grande, sem sombra -, que e
   a forma que estas paginas ja usam para dizer «isto e um bloco».
   Uma so forma para o mesmo papel, em toda a zona. */
.auth-box{
    border:1px solid var(--line); border-radius:var(--r-lg); background:#fff;
    padding:30px 30px 32px;
}
.auth-box h1{ font-size:26px }
.auth-sub{ color:var(--muted); font-size:14px; margin-top:9px }

/* 🚨 SCOPE: estas regras tem de morder em `.auth-box` e NAO em `.auth`.
   O `.auth` e o embrulho da pagina real; os estados desenhados na
   maqueta usam so a `.auth-box`, logo tudo o que estivesse preso ao
   `.auth` nao lhes chegava. Era isso que fazia os botoes aparecerem com
   a largura natural e colados ao campo de cima: nao era espacamento a
   menos, era a regra a nao aplicar-se.
   A licao e geral e vale para o resto da folha: se um bloco tem de
   poder viver sozinho num estado da maqueta, as regras dele prendem-se
   ao PROPRIO bloco e nunca a um antepassado que so existe na pagina. */

/* A faixa de contexto. Existe por duas razões e não por enfeite: diz
   PORQUE é que se está a pedir um SMS (senão é um pedido a seco no meio
   de uma montra pública), e é o que sobrevive ao desvio de «completar
   perfil» que a primeira entrada obriga. */
/* ⛔ SEM USO desde 2026-08-31: a faixa de contexto saiu do signin.html (decisao do
   Peter). Fica aqui, ao contrario do que se fez com CSS morto em producao, porque
   esta folha e SO da maqueta - nao e servida a ninguem, logo nao custa bytes - e o
   componente esta resolvido caso a faixa volte. O porque da saida esta no comentario
   do proprio signin.html. */
.auth-ctx{
    display:flex; align-items:center; gap:13px; margin-bottom:18px;
    background:var(--brand-soft); border-radius:var(--r-box); padding:12px 14px;
}
.auth-ctx .thumb{ width:46px; height:46px; border-radius:var(--r-box); flex:0 0 auto; overflow:hidden; position:relative }
.auth-ctx small{ display:block; color:var(--brand-ink); font-size:11.5px; letter-spacing:.06em; text-transform:uppercase; font-family:var(--f-head) }
.auth-ctx b{ display:block; font-family:var(--f-head); font-weight:400; color:var(--ink); font-size:14.5px; line-height:1.3; margin-top:3px }

.field{ margin-top:20px }
.lbl{ display:block; font-size:13px; color:var(--body); margin-bottom:7px }

/* 16px é o mínimo que impede o Safari de dar zoom ao focar um campo.
   Abaixo disso o telemóvel salta e desalinha a página inteira. */
.inp{
    width:100%; height:50px; padding:0 15px;
    border:1px solid var(--line); border-radius:var(--r-box); background:#fff;
    font:inherit; font-size:16px; color:var(--ink); outline:none;
}
.inp:focus{ border-color:var(--brand); box-shadow:0 0 0 3px rgba(77,189,230,.18) }
.inp::placeholder{ color:#9CB0BA }

.tel{ display:flex; gap:9px }
.tel select.inp{ width:126px; flex:0 0 auto }
.tel .inp:last-child{ flex:1 1 auto }

/* O PIN é UM campo, não quatro caixas. Quatro caixas são bonitas e
   partem o `autocomplete="one-time-code"`, que é o que faz o telemóvel
   oferecer o código do SMS sem ninguém o copiar. E um campo só continua
   a funcionar sem JavaScript, que quatro caixas nunca fazem. */
.pin{
    height:64px; text-align:center;
    font-family:var(--f-head); font-size:30px; letter-spacing:.5em; text-indent:.5em;
}

.auth-box .btn{ width:100%; margin-top:28px; height:52px }
/* Dois botoes empilhados (confirmar / rever) nao levam o mesmo respiro que o primeiro leva
   ao campo de cima: entre eles sao um par, e 28px lia-se como duas decisoes separadas. */
.auth-box .btn + .btn{ margin-top:12px }
.auth-note{ display:flex; align-items:flex-start; gap:9px; margin-top:16px; font-size:13px; color:var(--muted) }
.auth-note i{ margin-top:3px; font-size:12px }
.auth-gift{ color:var(--brand-ink) }
.auth-gift b{ font-family:var(--f-head); font-weight:400 }

.auth-err{
    display:flex; align-items:flex-start; gap:9px; margin-top:18px;
    background:#FDF0EE; color:#B3392A; border-radius:var(--r-box); padding:12px 14px; font-size:13.5px; line-height:1.45;
}
.auth-err i{ margin-top:2px; flex:0 0 auto }

/* A CONFIRMAÇÃO DE QUE UMA ESCRITA CORREU BEM. Não existia no site, e não era esquecimento:
   até às Definições, toda a escrita acabava num reencaminhamento (entrar, sair, resgatar) ou
   numa mudança de estado tão visível que dispensava a frase. Aqui a pessoa fica na mesma
   página e mexe em coisas que podem não mudar nada no ecrã - um interruptor guardado é
   indistinguível de um interruptor por guardar.
   ⚠️ Espelha a `.auth-err` de propósito, com a cor trocada: duas gramáticas de aviso no mesmo
   site divergem, e essa já é a que existe. */
.ok-note{
    display:flex; align-items:flex-start; gap:9px; margin-top:18px;
    background:#EAF6EF; color:#1E6B41; border-radius:var(--r-box); padding:12px 14px; font-size:13.5px; line-height:1.45;
}
.ok-note i{ margin-top:2px; flex:0 0 auto }

.auth-foot{ display:flex; align-items:center; gap:14px; margin-top:20px; font-size:13.5px; color:var(--muted); flex-wrap:wrap }
.auth-foot a{ color:var(--brand-ink) }
.auth-foot .wait{ margin-left:auto; color:#9CB0BA }

.auth-legal{ margin-top:22px; text-align:center; font-size:12.5px; color:var(--muted); line-height:1.6 }
.auth-legal a{ color:var(--brand-ink); text-decoration:underline }


/* ==================================================================
   COMPLETAR PERFIL
   Mesma caixa da porta, um pouco mais larga porque são quatro campos.
   ================================================================== */

.auth-wide{ max-width:520px }

/* O cadeado. Na APP é uma linha cinzenta por baixo de cada um dos três
   campos; aqui agrupa-se num aviso só, à cabeça, porque três avisos
   iguais seguidos deixam de se ler. */
.lockbox{
    display:flex; gap:12px; margin-top:22px;
    background:var(--soft); border:1px solid var(--line); border-radius:var(--r-box); padding:14px 15px;
}
.lockbox i{ color:var(--muted); font-size:14px; margin-top:2px }
.lockbox p{ font-size:13px; color:var(--body); line-height:1.55 }
.lockbox a{ color:var(--brand-ink); text-decoration:underline }
.lockbox .k{ color:var(--ink) }

.two{ display:grid; grid-template-columns:1fr 1fr; gap:14px }


/* ==================================================================
   O HUB - cartão + vouchers

   O cartão à esquerda e os vouchers à direita, e não empilhados: num
   ecrã largo o cartão empilhado empurra os vouchers para fora da
   primeira dobra, e os vouchers são o que se vem cá ver mais vezes.
   No telemóvel a ordem do DOM manda e o cartão fica em cima, que é onde
   tem de estar - é ele que se mostra ao balcão.
   ================================================================== */

.me-in{ padding-block:34px 70px }
.me-grid{ display:grid; grid-template-columns:330px 1fr; gap:34px; align-items:start }

/* ==================================================================
   O CARTAO

   Saiu-lhe a COR, nao a forma (regra do Peter, 2026-08-30, corrigida a
   seguir por ele proprio): o que ali estava a mais era o degrade da
   marca por cima do QR, nao a moldura. Cheguei a tirar as duas coisas e
   estava a ir longe de mais.

   Fica um cartao com o mesmo desenho das Definicoes e do cartao de
   informacao do comerciante - contorno de um pixel, canto grande, sem
   sombra, seccoes separadas por risco fino. Sem enchimento de cor
   nenhum, por tres razoes:
     · um QR precisa de zona calma a volta;
     · nesta pagina a cor ja e usada onde CONTA (o estado dos vouchers,
       o aviso de pontos a prazo). Gasta em fundo, deixa de chamar a
       atencao onde e precisa;
     · o cartao nao e a marca: e a identificacao da pessoa.
   ================================================================== */

.idcard{ border:1px solid var(--line); border-radius:var(--r-lg); overflow:hidden; background:#fff }

/* A identidade e uma linha de texto e nao um cabecalho pintado. */
.idcard-top{ display:flex; align-items:center; gap:14px; padding:20px; border-bottom:1px solid var(--line) }
.idcard-top b{ display:block; font-family:var(--f-head); font-weight:400; font-size:18px; line-height:1.25; color:var(--ink) }
.idcard-top small{ display:block; font-size:12.5px; color:var(--muted); margin-top:2px }

/* O QR e o heroi: preto sobre branco, com margem larga. Sem moldura
   propria - a do cartao ja o limita, e duas molduras encaixadas sao uma
   a mais. */
.idcard-qr{ padding:28px 20px 24px; text-align:center; border-bottom:1px solid var(--line) }
.idcard-qr .qr{ width:180px; height:180px; display:block; margin:0 auto }
.qr path{ fill:var(--ink) }
.idcard-qr p{ font-size:12.5px; color:var(--muted); margin-top:16px; line-height:1.5 }

/* 🚨 A linha do telefone SUBSTITUI o codigo curto que a APP mostra por
   baixo do QR. Na APP escreve-se `user_id.slice(0,8)`, e esses 8
   caracteres NAO IDENTIFICAM NINGUEM: o `identify` do Office so aceita
   `user_id` com 32 caracteres, ou o numero de telefone (o mesmo vale
   para o CHECK_USER da API externa). Ou seja, o codigo que a APP mostra
   como recurso nao funciona como recurso. O que funciona e o numero. */
.idcard-alt{ display:flex; align-items:center; gap:11px; padding:15px 20px; font-size:13px; border-bottom:1px solid var(--line) }
.idcard-alt i{ color:var(--muted) }
.idcard-alt b{ font-family:var(--f-head); font-weight:400; color:var(--ink); margin-left:auto }

/* Os dois numeros, sem cor de enchimento.
   ⚠️ Em Poppins e nao em Anton - ver a nota dos NUMEROS no site.css. */
.idcard-foot{ display:grid; grid-template-columns:1fr 1fr }
.idcard-foot div{ padding:16px 20px }
.idcard-foot div + div{ border-left:1px solid var(--line) }
.idcard-foot small{ display:block; font-size:11px; letter-spacing:.08em; text-transform:uppercase; color:var(--muted); font-family:var(--f-head) }
.idcard-foot b{
    display:block; font-family:var(--f-head); font-weight:400; color:var(--ink);
    font-size:32px; line-height:1; margin-top:8px; letter-spacing:-.03em; font-variant-numeric:tabular-nums;
}

/* ⏳ PARQUEADO (2026-08-30): o convite a instalar a APP sai da maqueta
   ate a APP estar publica. O estilo fica, porque o lugar dele ja esta
   decidido - por baixo do cartao, como na APP - e depende so de
   `app_install.enabled`, hoje FALSE. Desaparece por inteiro no sistema
   onde o `..._url` e null, que hoje e o iOS.
.inst{
    display:flex; align-items:center; justify-content:center; gap:10px;
    margin-top:14px; width:100%; height:46px; border-radius:var(--r-pill);
    border:1px solid var(--line); background:#fff; font-family:var(--f-head); font-size:14px; color:var(--ink);
}
.inst i{ font-size:16px; color:var(--brand-ink) }
*/

/* Aviso de pontos em risco. É um BOTÃO e leva ao detalhe, porque o
   aviso sem a lista não diz onde é que os pontos estão a morrer. */
.pp-warn{
    display:flex; align-items:center; gap:12px; width:100%; text-align:left;
    margin-bottom:22px; padding:14px 16px; border-radius:var(--r-box);
    background:#FFF6E6; border:1px solid #F3DFB8; color:#8A6218; font-size:13.5px;
}
.pp-warn i:first-child{ font-size:16px }
.pp-warn i:last-child{ margin-left:auto; font-size:12px }

.pp-row{ display:flex; align-items:center; gap:13px; padding:14px 0; border-bottom:1px solid var(--line) }
.pp-row:last-child{ border-bottom:0 }
.pp-row .av{ background:var(--soft); color:var(--muted) }
.pp-row b{ display:block; font-family:var(--f-head); font-weight:400; color:var(--ink); font-size:14.5px }
.pp-row small{ display:block; color:var(--muted); font-size:12.5px; margin-top:2px }


/* ==================================================================
   LISTA DE VOUCHERS
   ================================================================== */

.sec-head{ display:flex; align-items:center; gap:16px; margin-bottom:18px; flex-wrap:wrap }
.sec-head h2{ font-size:22px }

.seg{ display:flex; gap:6px; margin-left:auto; background:var(--soft); border-radius:var(--r-pill); padding:4px }
.seg a{ height:34px; padding:0 16px; display:grid; place-items:center; border-radius:var(--r-pill); font-size:13.5px; color:var(--body) }
.seg a.on{ background:#fff; color:var(--ink); box-shadow:var(--sh-1) }

.vlist{ display:flex; flex-direction:column; gap:10px }

.vrow{
    display:flex; align-items:center; gap:15px; padding:15px 18px;
    border:1px solid var(--line); border-radius:var(--r-card); background:#fff;
    transition:border-color .15s, box-shadow .15s;
}
.vrow:hover{ border-color:#CFDCE4; box-shadow:var(--sh-1) }
.vrow.dim{ background:var(--soft) }
.vrow.dim .vrow-main b{ color:var(--body) }

/* ⚠️ Iniciais e não logótipo, porque o `GET vouchers` NÃO devolve o
   logótipo do comerciante (não há `merchant_logo_src` no SELECT - a APP
   resolve-o exactamente assim). Acrescentá-lo é barato e segue a
   convenção `*_src` do projecto; fica anotado no fim da página. */
.vrow .av{ width:44px; height:44px; font-size:15px }

.vrow-main{ flex:1 1 auto; min-width:0 }
.vrow-main b{ display:block; font-family:var(--f-head); font-weight:400; font-size:15.5px; color:var(--ink); line-height:1.3 }
.vrow-main small{ display:block; color:var(--muted); font-size:13px; margin-top:3px }
.vrow-end{ text-align:right; flex:0 0 auto; display:flex; flex-direction:column; align-items:flex-end; gap:6px }
.vrow-when{ font-size:12.5px; color:var(--muted) }

.vbadge{
    display:inline-flex; align-items:center; gap:6px; height:26px; padding:0 11px;
    border-radius:var(--r-pill); font-size:12px; font-family:var(--f-head);
}
.vb-on{ background:#E4F6EC; color:#1E7A4C }
.vb-used{ background:var(--soft); color:var(--muted) }
.vb-exp{ background:#FDF0EE; color:#B3392A }
.vb-cancel{ background:var(--soft); color:var(--muted) }

.vcode{ font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; letter-spacing:.06em }

.empty{ text-align:center; padding:56px 20px; border:1px dashed var(--line); border-radius:var(--r-lg) }
.empty i{ font-size:26px; color:#C3D5DE }
.empty h3{ font-size:17px; margin-top:14px }
.empty p{ color:var(--muted); font-size:14px; margin-top:7px }
.empty .btn{ margin-top:20px }


/* ==================================================================
   DETALHE DO VOUCHER
   ================================================================== */

.vd-in{ padding-block:26px 70px }
.vd{ display:grid; grid-template-columns:1fr 380px; gap:40px; align-items:start }

.vd-mrch{ display:flex; align-items:center; gap:14px; padding-bottom:20px; border-bottom:1px solid var(--line); margin-bottom:24px }
.vd-mrch b{ font-family:var(--f-head); font-weight:400; font-size:16px; color:var(--ink) }
.vd-mrch small{ display:block; color:var(--muted); font-size:13px; margin-top:2px }
.vd-mrch .go{ margin-left:auto; color:var(--muted); font-size:13px }

.vd h1{ font-size:clamp(22px,2.6vw,30px) }

/* 🚨 O CÓDIGO ANTES DO QR, e é a divergência maior desta zona.
   Na APP o QR manda, porque o telemóvel está sempre na mão de quem o
   mostra. No site, boa parte das visitas são de computador, e um
   portátil não se estende por cima de um balcão. O que atravessa os
   dois é o código: lê-se, dita-se, copia-se, imprime-se. O QR fica logo
   abaixo, inteiro, para quem estiver ao telemóvel. */
.vcodebox{ border:1px solid var(--line); border-radius:var(--r-lg); overflow:hidden; background:#fff; box-shadow:var(--sh-1) }
.vcodebox .top{ padding:22px; text-align:center }
.vcodebox small{ font-size:11px; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); font-family:var(--f-head) }
.vcodebox .code{ font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size:23px; color:var(--ink); margin-top:10px; letter-spacing:.06em }
.vcodebox .copy{
    display:flex; align-items:center; justify-content:center; gap:9px; width:100%; height:46px;
    background:var(--brand-soft); color:var(--brand-ink); font-family:var(--f-head); font-size:14px;
    border-top:1px solid var(--line);
}
.vcodebox .copy:hover{ background:#DCF0F9 }
.vcodebox .qrwrap{ border-top:1px solid var(--line); padding:22px; text-align:center }
.vcodebox .qrwrap .qr{ width:160px; height:160px; margin:0 auto; display:block }
.vcodebox .qrwrap p{ font-size:12.5px; color:var(--muted); margin-top:12px }

.vd-rules{ border:1px solid var(--line); border-radius:var(--r-lg); padding:6px 20px; margin-top:16px }
.vd-rules .r{ display:flex; align-items:center; gap:14px; padding:12px 0; font-size:13.5px; border-bottom:1px solid var(--line) }
.vd-rules .r:last-child{ border-bottom:0 }
.vd-rules .r span{ color:var(--muted) }
.vd-rules .r b{ margin-left:auto; font-family:var(--f-head); font-weight:400; color:var(--ink) }

.vd-gone{ display:flex; gap:12px; background:#FDF0EE; border-radius:var(--r-box); padding:16px; color:#B3392A; font-size:13.5px }
.vd-gone i{ font-size:18px; margin-top:1px }
.vd-gone b{ display:block; font-family:var(--f-head); font-weight:400 }
.vd-gone span{ color:#8A4A40 }


/* ===== A OFERTA, dentro do voucher =====
   🚨 UM VOUCHER TEM DE CONTINUAR A EXPLICAR-SE DEPOIS DE A CAMPANHA
   MORRER (regra do Peter, 2026-08-30, e e a razao de o conteudo vir
   AQUI e nao de um `GET camps/{id}`).

   O `GET vouchers/{id}` ja faz `LEFT JOIN camp t1` e so tira de la o
   `title`. Basta alargar o SELECT (`caption`, `picture`, `details`,
   `terms`) e o voucher passa a trazer a sua propria copia do que e.
   Ir buscar a campanha ao endpoint publico seria fragil de propria: ele
   tem portoes (publicada, dentro da janela, comerciante spot, gate 18+),
   logo uma campanha terminada devolveria `not_found` - e o voucher
   continua valido e a pessoa continua a precisar de saber o que traz ao
   balcao. O rich text le-se sanitizado em `url_only`, como no resto.

   Fica INLINE e nao num modal: isto e a razao de a pagina existir, e
   esconder atras de um botao o que se veio ler e esconder o assunto. As
   CONDICOES e que ficam dobradas, num `<details>` nativo - que abre sem
   uma linha de JavaScript, o que importa numa zona onde ler funciona
   sem ele. */
.vcamp{ margin-top:26px; padding-top:26px; border-top:1px solid var(--line) }
.vcamp h2{ font-size:17px; margin-bottom:14px }
.vcamp-top{ display:flex; gap:18px; align-items:flex-start; margin-bottom:16px }
.vcamp-shot{ width:190px; flex:0 0 auto; aspect-ratio:16/9; border-radius:var(--r-media); overflow:hidden; position:relative }
.vcamp-shot img{ width:100%; height:100%; object-fit:cover }
.vcamp-cap{ font-size:15.5px; line-height:1.6; color:var(--body) }

/* ⚠️ AS CONDICOES REUSAM O `details.terms` DO detail.css, que ja existe
   e ja e usado pela pagina da campanha. Aqui chegou a haver uma copia
   chamada `.vterms`, e ela deu logo os dois defeitos que uma copia da:
   a seta nao aparecia, e o texto ficava encostado a esquerda.

   🚨 A CAUSA DOS DOIS ERA A MESMA, e vale a pena reter: o escape do
   icone dentro do `content` ficou mal escrito e deixou la um caractere
   de controlo. Em CSS isso e uma STRING POR FECHAR, e o parser, ao
   recuperar do erro, ENGOLE as regras seguintes - foi assim que a regra
   do padding desapareceu sem ninguem lhe ter tocado. Um escape mau num
   `content` nao estraga so o icone: estraga o que vem a seguir.

   A correccao nao foi arranjar a copia, foi deita-la fora. So fica o
   espaco por cima, que e a unica coisa que e desta pagina: */
.vcamp details.terms{ margin-top:20px }

/* Sem campanha (desconto directo, ou um comp sem campanha): nao ha nada
   a mostrar, e o bloco desaparece. O que fica e uma linha a dizer o que
   e - senao a pessoa procura uma oferta que nunca existiu. */
.vcamp-none{ display:flex; gap:12px; margin-top:26px; padding-top:26px; border-top:1px solid var(--line); font-size:14px; color:var(--muted) }
.vcamp-none i{ margin-top:3px; color:var(--muted) }

/* ===== Avaliação =====
   Quatro eixos, comentário opcional, e a janela de 15 dias depois do
   uso - que o servidor impõe e a APP nunca diz a ninguém. Aqui diz-se:
   um formulário que desaparece sem explicação lê-se como avaria. */
.rate-box{ border:1px solid var(--line); border-radius:var(--r-lg); padding:24px; margin-top:26px }
.rate-box h3{ font-size:17px }
.rate-box > p{ color:var(--muted); font-size:13.5px; margin-top:7px }

.rax{ display:flex; align-items:center; gap:16px; padding:14px 0; border-bottom:1px solid var(--line) }
.rax span{ font-size:14px; color:var(--body) }
.rax .st{ margin-left:auto; display:flex; gap:5px }
.rax .st i{ font-size:21px; color:#DCE6EC; cursor:pointer }
.rax .st i.on{ color:var(--star) }

.rate-box textarea{
    width:100%; margin-top:16px; min-height:96px; padding:13px 15px; resize:vertical;
    border:1px solid var(--line); border-radius:var(--r-box); font:inherit; font-size:14.5px; color:var(--ink); outline:none;
}
.rate-box textarea:focus{ border-color:var(--brand); box-shadow:0 0 0 3px rgba(77,189,230,.18) }
.rate-warn{ display:flex; gap:9px; margin-top:14px; font-size:13px; color:var(--muted) }
.rate-warn i{ margin-top:3px; font-size:12px }

.said{ border:1px solid var(--line); border-radius:var(--r-lg); padding:22px; margin-top:26px }
.said h3{ font-size:15px }
.said .txt{ font-size:14.5px; color:var(--body); margin-top:10px; white-space:pre-wrap }
.said .reply{ border-left:3px solid var(--brand); padding-left:14px; margin-top:20px }
.said .reply small{ display:block; color:var(--muted); font-size:12.5px }
.said .stars-ro{ display:flex; gap:4px; margin-top:8px; color:var(--star); font-size:14px }
.said .stars-ro .off{ color:#DCE6EC }


/* ==================================================================
   FAVORITOS  (/conta/favoritos)

   🚨 SAO DUAS COISAS DIFERENTES NA MESMA TABELA, e o ecra tem de as
   separar com DUAS PALAVRAS:

     · comerciante (`camp_id` NULL) = SEGUIR. Acende as notificacoes
       daquela loja (`_NOTIF_AUDIENCE_WHERE`), logo e um compromisso.
     · campanha (`camp_id` preenchido) = GUARDAR. Nao notifica nada,
       nao compromete nada, e so um marcador para voltar depois.

   Por isso o coracao fica SO no comerciante, e a campanha leva um
   MARCADOR de livro. Usar o mesmo coracao nos dois era repor a
   ambiguidade que tirou o coracao do cartao dos pontos.
   ================================================================== */

.fav-group{ margin-bottom:44px }
.fav-group:last-child{ margin-bottom:0 }
.fav-group > p{ color:var(--muted); font-size:13.5px; margin:-8px 0 18px }

/* Uma loja seguida e uma LINHA, nao um cartao: aqui a pessoa vem
   confirmar ou desfazer, nao vem descobrir. Cartoes convidariam a
   escolher, e nao ha nada a escolher. */
.mrow{
    display:flex; align-items:center; gap:15px; padding:14px 18px;
    border:1px solid var(--line); border-radius:var(--r-card); background:#fff;
}
.mrow:hover{ border-color:#CFDCE4 }
.mrow .av{ width:46px; height:46px; font-size:15px }
.mrow-main{ flex:1 1 auto; min-width:0 }
.mrow-main b{ display:block; font-family:var(--f-head); font-weight:400; font-size:15.5px; color:var(--ink) }
.mrow-main small{ display:block; color:var(--muted); font-size:13px; margin-top:3px }

/* ⚠️ Uma oferta guardada que JA NAO ESTA DISPONIVEL nao desaparece em
   silencio: fica em marca d'agua, a dizer o que aconteceu, com o botao
   de a tirar da lista. Desaparecer sem explicacao le-se como avaria.

   🚨 MAS ISSO SO VALE PARA A INDISPONIBILIDADE. Os portoes de
   MODERACAO e de COMPLIANCE (merchant `BLOCKED`, `SUSPECT` fora da
   graca, e o gate 18+) tiram a linha POR INTEIRO, sem lapide: um
   marcador com o titulo la dentro seria uma porta lateral para
   conteudo que a plataforma decidiu esconder, e e exactamente o que o
   §6.2 do estudo manda evitar. */
.card.gone{ opacity:.55 }
.card.gone .card-img{ filter:grayscale(1) }
.gone-note{
    display:flex; align-items:center; gap:9px; padding:10px 12px; margin-top:10px;
    background:var(--soft); border-radius:var(--r-box); font-size:12.5px; color:var(--muted);
}
.gone-note button{ margin-left:auto; color:var(--brand-ink); font-size:12.5px; flex:0 0 auto }

/* ==================================================================
   BLOQUEADOS

   Vive DENTRO das Definicoes e nao numa pagina propria: e uma lista de
   manutencao, quase sempre vazia, e nao um destino. Os favoritos sao um
   destino; estes sao um acerto que se faz uma vez.
   ================================================================== */

.blk-row{ display:flex; align-items:center; gap:13px; padding:14px 0; border-bottom:1px solid var(--line) }
.blk-row:last-child{ border-bottom:0 }
.blk-row .av{ width:40px; height:40px; font-size:14px; background:var(--soft); color:var(--muted) }
.blk-row b{ display:block; font-family:var(--f-head); font-weight:400; font-size:14.5px; color:var(--ink) }
.blk-row small{ display:block; color:var(--muted); font-size:12.5px; margin-top:2px }
.blk-row .btn{ margin-left:auto; flex:0 0 auto }

/* ===== Denunciar: os motivos =====
   Sao o SET de nove que a `content_report.reasons` ja tem. Nao se
   inventa nenhum, e nao se esconde nenhum. */
.rsn{ display:flex; flex-direction:column; gap:2px; margin-top:16px; max-height:none }
.rsn label{ display:flex; align-items:center; gap:11px; padding:9px 0; font-size:14px; cursor:pointer }
.rsn input{ width:17px; height:17px; accent-color:var(--brand); flex:0 0 auto }
.dlg textarea{
    width:100%; margin-top:14px; min-height:80px; padding:12px 14px; resize:vertical;
    border:1px solid var(--line); border-radius:var(--r-box); font:inherit; font-size:14px; color:var(--ink); outline:none;
}
.dlg textarea:focus{ border-color:var(--brand); box-shadow:0 0 0 3px rgba(77,189,230,.18) }

/* Aviso duro dentro de um dialogo. Fundo quente e nao vermelho: isto
   avisa do que se perde, nao acusa ninguem de nada. */
.dlg-warn{
    display:flex; gap:11px; margin-top:18px; padding:13px 15px;
    background:#FFF6E6; border:1px solid #F3DFB8; border-radius:var(--r-box);
    font-size:13.5px; color:#8A6218; line-height:1.5;
}
.dlg-warn i{ margin-top:3px; flex:0 0 auto }

/* ===== Entrada discreta para denunciar/bloquear =====
   No fim do cartao de informacao, em texto pequeno. Nao entram na
   linha das accoes (telefone, seguir): essa e das accoes que a pessoa
   quer fazer, estas sao as que espera nunca ter de fazer. */
.imod{ display:flex; gap:18px; flex-wrap:wrap; font-size:13px }
.imod button{ color:var(--muted); display:inline-flex; align-items:center; gap:7px }
.imod button:hover{ color:var(--ink) }
.imod i{ font-size:11px }

/* ==================================================================
   DEFINIÇÕES
   Uma coluna só, com secções. A nav lateral foi considerada e caiu: com
   cinco blocos curtos, uma coluna de navegação ao lado de meia página
   de conteúdo é mobília a mais para o que aqui se faz - que é entrar,
   mudar uma coisa, e sair.
   ================================================================== */

.set-in{ padding-block:34px 80px }
.set{ max-width:620px }
.set > h1{ font-size:28px; margin-bottom:6px }
.set > .sub{ color:var(--muted); font-size:14px; margin-bottom:30px }

.sec{ border:1px solid var(--line); border-radius:var(--r-lg); padding:6px 22px; margin-bottom:18px }
.sec h3{ font-size:12px; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); font-family:var(--f-head); padding:18px 0 4px }
.row{ padding:16px 0; border-bottom:1px solid var(--line) }
.row:last-child{ border-bottom:0 }
.row .lbl{ margin-bottom:8px }

.row-flex{ display:flex; align-items:center; gap:16px }
.row-flex .lbl{ margin-bottom:0 }
.row-flex .val{ margin-left:auto; font-family:var(--f-head); color:var(--ink); font-size:14.5px }
.row-flex .act{ margin-left:auto; color:var(--brand-ink); font-size:13.5px }

/* Campo trancado: mostra o valor e diz porquê, com o caminho para o
   corrigir. Não é um `disabled` - um campo cinzento sem explicação
   parece uma avaria, e gera um contacto de suporte por cada pessoa. */
.ro{ display:flex; align-items:center; gap:12px }
.ro .val{ margin-left:auto; font-family:var(--f-head); color:var(--ink); font-size:14.5px }
.ro-note{ display:flex; align-items:flex-start; gap:8px; margin-top:8px; font-size:12.5px; color:var(--muted) }
.ro-note i{ margin-top:3px; font-size:10px }
.ro-note a{ color:var(--brand-ink); text-decoration:underline }

/* Interruptor. O da APP é um botão com um círculo lá dentro; aqui é um
   `<input type="checkbox">` a sério, porque um formulário do site tem de
   poder ser submetido e lido por um leitor de ecrã. */
.tgl{ position:relative; width:48px; height:28px; flex:0 0 auto; margin-left:auto }
.tgl input{ position:absolute; inset:0; opacity:0; margin:0; cursor:pointer; z-index:2 }
.tgl .track{ position:absolute; inset:0; background:#D6E2E9; border-radius:var(--r-pill); transition:background .18s }
.tgl .knob{ position:absolute; top:3px; left:3px; width:22px; height:22px; border-radius:50%; background:#fff; box-shadow:0 1px 3px rgba(15,27,36,.25); transition:left .18s }
.tgl input:checked ~ .track{ background:var(--brand) }
.tgl input:checked ~ .knob{ left:23px }
.tgl input:focus-visible ~ .track{ box-shadow:0 0 0 3px rgba(77,189,230,.3) }

.hint{ font-size:12.5px; color:var(--muted); margin-top:8px; line-height:1.55 }

.set-save{ display:flex; align-items:center; gap:16px; margin-top:26px }
.set-save .btn{ min-width:190px }

/* Apagar a conta. Fora da caixa e no fim, em texto e não em botão: é
   irreversível e não deve competir com «Guardar». */
.danger{ margin-top:40px; padding-top:26px; border-top:1px solid var(--line) }
.danger h3{ font-size:15px; color:var(--ink) }
.danger p{ font-size:13.5px; color:var(--muted); margin-top:8px; max-width:52ch }
/* ⚠️ O `summary` entra no MESMO selector do `<a>` e não num vizinho: em produção quem abre isto
   é a revelação, na maqueta era um link, e as duas têm de se ler exactamente igual - um texto
   sublinhado, nunca um botão. É irreversível, e não pode competir com «Guardar». */
.danger a,
.danger .dsc > summary{ display:inline-block; margin-top:14px; color:#C0392B; font-size:13.5px; text-decoration:underline }

/* Alteração de email: três estados no mesmo sítio (ver, escrever, PIN). */
.em-steps{ display:flex; gap:10px; margin-top:12px; flex-wrap:wrap }
.em-pending{ font-size:13px; color:var(--muted); margin-bottom:10px }
.em-pending b{ color:var(--ink) }

/* AS DUAS REVELAÇÕES DESTA PÁGINA - «Alterar email» e «Apagar a conta».
   🚨 `<details>` e não JavaScript, que é o padrão que o site já usa quatro vezes (o horário do
   comerciante, o painel de filtros do /spots, o FAQ da homepage e o menu do utilizador). E aqui
   não é só coerência: sem ele, ir de «ver o email» para «escrever o novo» obrigava a inventar um
   estado que o SERVIDOR não tem. Ele conhece dois - nada pendente, ou à espera do PIN - e o
   terceiro ecrã da maqueta é só um formulário. Pô-lo num `?passo=` seria criar estado no
   endereço para uma coisa que o browser sabe guardar sozinho.
   ⚠️ O triângulo nativo sai pelas duas vias, como no `.me > summary`: os browsers antigos usam
   o `::-webkit-details-marker` e os novos o `list-style`. Sem as duas, um deles fica. */
.dsc > summary{ list-style:none; cursor:pointer }
.dsc > summary::-webkit-details-marker{ display:none }
.dsc > summary::marker{ content:'' }
.dsc[open] > summary{ margin-bottom:16px }


/* Os estilos de maqueta (.mock, .mock-grid, .state-tag) vivem no
   site.css, na folha que TODAS as paginas carregam: sao a convencao de
   desenhar os estados lado a lado e ja e usada por quatro paginas. Uma
   segunda copia aqui era o inicio da divergencia do costume.
   So o que e especifico desta zona fica: */
/* Na maqueta os estados ficam um pouco mais apertados, para caberem
   tres por linha. A caixa e a mesma da producao. */
.mock .auth-box{ padding:26px 24px 28px }

/* ==================================================================
   RESPONSIVO
   ================================================================== */

@media (max-width:1100px){
    .me-grid{ grid-template-columns:290px 1fr; gap:26px }
    .vd{ grid-template-columns:1fr; gap:28px }
}

@media (max-width:860px){
    /* 🚨 padding-block, nunca `padding:Npx 0`: estes elementos SÃO o .wrap. */
    .auth-in{ padding-block:32px 56px; display:block }
    .me-in{ padding-block:24px 56px }
    .vd-in{ padding-block:20px 56px }
    .set-in{ padding-block:24px 60px }

    /* O cartão volta a ficar em cima, que é a ordem do DOM. Sem a
       moldura que tinha, precisa de um risco a separá-lo dos vouchers:
       empilhados, o espaço sozinho não chega para se ler como duas
       coisas diferentes. */
    .me-grid{ grid-template-columns:1fr; gap:30px }

    .auth{ max-width:none }
    .auth-box{ padding:24px 20px 26px }

    .sec{ padding-inline:16px }
    .seg{ margin-left:0; width:100% }
    .seg a{ flex:1 1 0 }
}

@media (max-width:560px){
    .two{ grid-template-columns:1fr }
    .vrow{ padding:13px 14px; gap:12px }
    .vrow .av{ width:38px; height:38px; font-size:13px }
    .vrow-main b{ font-size:14.5px }
    .idcard-qr .qr{ width:150px; height:150px }
    .row-flex{ flex-wrap:wrap }
    .set-save{ flex-direction:column; align-items:stretch }
}

/* ==================================================================
   A NAVEGACAO DA ZONA PESSOAL  -  fila em ecra largo, dropdown em estreito
   ==================================================================

   🚨 NAO E UM COMPONENTE NOVO: sao as DUAS pecas que o site ja tem, coladas.
   A fila e o `.seg` (o selector de tres do `/spots`, e o Activos/Historico
   desta pagina); o painel do dropdown e o `.me-menu` (o menu do utilizador,
   no cabecalho). O que se acrescenta e o `<details>` que troca um pelo outro,
   e mais nada. Uma segunda gramatica de separadores neste site divergiria.

   🚨 E FUNCIONA SEM JAVASCRIPT, nas duas formas. A fila sao `<a>` reais (logo
   cada separador tem endereco proprio, o «voltar» do browser funciona e o
   `?next=` tambem) e o dropdown e um `<details>`, que abre e fecha sozinho.
   Nao ha aqui uma segunda escrita dos ecras em JS.
   ⚠️ O `<details>` NAO fecha ao tocar fora - e o mesmo custo do painel do
   `/spots`, e resolve-se com o `head.js` que ja existe, no dia em que
   incomodar. Fica dito, nao fica escondido.

   ⚠️ A MARCACAO E DUPLICADA no DOM, e e o preco desta abordagem. Nao ha forma
   de fazer isto com uma marcacao so: o `open` de um `<details>` nao se forca
   por CSS, e sobrepor-se ao modo como o browser esconde o conteudo de um
   `<details>` fechado e um truque que varia entre browsers. As alternativas
   sao piores: um `<select>` a navegar parte sem JavaScript (licao ja paga no
   painel de filtros do `/spots`), e deixar a fila deslizar na horizontal
   esconde o que nao cabe sem forma de pôr o activo a vista.
   ✅ E o custo e pequeno e mensuravel: ~300 bytes, e o que esta em
   `display:none` NAO e anunciado por um leitor de ecra, logo quem usa um
   ouve exactamente UMA lista. Em producao as duas saem do MESMO array em
   PHP, ou seja a fonte tem um dono so.

   🚨 A LARGURA E FIXA E NAO SE REMEDE (decisao do Peter, 2026-09-08). Abaixo
   dela e SEMPRE dropdown, sejam quantos forem os separadores e diga o que
   disser a traducao. A versao anterior era condicional - «o gatilho e o 4.o
   separador, e o ponto de troca mede-se quando la chegarmos» - e isso e uma
   coisa para alguem se lembrar, que e o genero de coisa que se esquece. Uma
   largura fixa e uma GARANTIA, e o componente deixa de precisar de manutencao.

   O 640 nao e um numero medido: e uma frase. **Um telemovel leva dropdown;
   tablet e computador levam a fila.**

   🚨 E O QUE TORNA A REGRA FIXA SEGURA E O `flex-wrap`, mais nada. Acima de 640
   a fila ainda tem de CABER, e a 641 so ha 590px. Medido: seis separadores
   precisam de 722 e a pagina passava a transbordar (`scrollWidth` 740 contra
   641); sete davam 860. Com o `flex-wrap` passam a duas linhas e a pagina fica
   em 626 - e com os cinco de hoje nada muda (uma linha, 581). Ou seja a regra
   fixa deixa de ter tecto nenhum a lembrar.

   ⚠️ E UMA CORRECCAO, porque este comentario ja disse o contrario: eu tinha
   escrito que o ponto de troca se media em ALEMAO. Medido com rotulos de
   SEPARADOR (e nao com os rotulos de seccao que eu tinha usado), o `de` da 575
   e o `pt` da 581 - o portugues e que e o pior caso. O principio mantinha-se;
   a conclusao estava errada. Com a largura fixa a questao deixa de existir.
   ================================================================== */

.zt{ margin-bottom:22px }

/* A FILA. E o `.seg`, com tres diferencas e todas com razao:
   - sem o `margin-left:auto`, que existe para o encostar a direita de um
     `.sec-head` e aqui o mandaria para o canto;
   - com icone ao lado do nome, porque em ecra estreito o icone e o que se
     reconhece antes de se ler;
   - `white-space:nowrap`, senao um rotulo longo parte a meio dentro da pilula. */
/* ⚠️ `width:fit-content` e nao a largura toda: o `.seg` e um bloco, logo por
   omissao estica ate ao fim da linha e desenha uma pilula cinzenta quase vazia
   com os separadores encostados a esquerda. Abracar o conteudo e o que o `.seg`
   ja faz no resto do site, onde o `margin-left:auto` o encolhe contra a direita.
   🚨 E ganha ao `width:100%` do `@media (max-width:860px)` por vir DEPOIS no
   ficheiro com a mesma especificidade - o que aqui e o que se quer, e nao um
   acaso: entre 640 e 860 a fila cabe (precisa 582, tem 590 no pior caso). */
.seg-nav{ margin-left:0; width:fit-content; flex-wrap:wrap }
.seg-nav a{ display:flex; align-items:center; gap:8px; white-space:nowrap }
.seg-nav a i{ font-size:12px; color:var(--muted) }
.seg-nav a.on i{ color:var(--brand-ink) }

/* O DROPDOWN. Escondido por omissao: em ecra largo a fila e melhor, porque
   mostra tudo de uma vez e resolve-se num toque. */
.zt-dd{ display:none; position:relative }
.zt-dd > summary{ list-style:none; cursor:pointer }
.zt-dd > summary::-webkit-details-marker{ display:none }
.zt-dd > summary::marker{ content:'' }

.zt-btn{
    display:flex; align-items:center; gap:11px; height:44px; padding:0 16px;
    background:var(--soft); border-radius:var(--r-pill);
    font-size:14.5px; color:var(--ink);
}
.zt-btn > i:first-child{ font-size:13px; color:var(--brand-ink) }
.zt-btn > span{ flex:1 1 auto; font-weight:600 }
.zt-btn > i:last-child{ font-size:10px; color:var(--muted); transition:transform .15s }
.zt-dd[open] .zt-btn > i:last-child{ transform:rotate(180deg) }

/* O painel E o `.me-menu`; so a colocacao muda. Escrito com as duas classes
   (0,2,0) e nao com `.zt-menu` sozinha, para ganhar por ESPECIFICIDADE e nao
   por ordem de ficheiro - a base vive no `site.css` e esta regra no
   `account.css`, e a licao da ordem ja foi paga tres vezes nesta folha. */
.me-menu.zt-menu{ position:static; margin-top:8px; min-width:0; width:100% }
.me-menu.zt-menu a.on{ background:var(--soft); font-weight:600 }
.me-menu.zt-menu a.on i{ color:var(--brand-ink) }

/* 🚨 LARGURA FIXA: abaixo daqui e sempre dropdown, independentemente de quantos
   separadores houver ou do idioma. Nao se remede. Ver o cabecalho. */
@media (max-width:640px){
    .zt-row{ display:none }
    .zt-dd{ display:block }
}
