/* Garrafeira — todo o CSS da app.
   Segunda pele ("charme"): o esqueleto é o mesmo (mesmas classes, mesmos
   ecrãs), o que mudou foi a linguagem visual — papel em vez de cinzento,
   serifa (Fraunces) para os nomes e os números, e uma regra de cor só:
   bordô = a app, dourado = distinção (menção/nota), tudo o resto é
   neutro. Antes cada crachá tinha a sua cor e o cartão parecia um saco
   de autocolantes; agora a cor é informação. */

/* Bloqueia pinch-zoom e double-tap zoom (iOS PWA) */
*{touch-action:manipulation}
html,body{touch-action:pan-x pan-y}
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}

:root{
  --vh:#7b1f3d;--vh2:#9c2a4e;--vhp:#f9edf1;--vhd:#4e1228;
  --ou:#b0842c;--oup:#fbf4e4;--ou2:#8a6508;
  --bg:#f6f1ea;--bg2:#efe7dd;--card:#fffdfb;--tx:#241d1c;--mu:#7a6d68;
  --bo:#e8dfd4;--bo2:#d9cec0;--dg:#b3261e;--dgp:#fdeceb;
  --in:#31597e;--inp:#eaf1f8;--vd:#3d6b52;--vdp:#eaf2ed;
  --r:14px;--r2:18px;
  --ff:'Inter',system-ui,-apple-system,sans-serif;
  --fd:'Fraunces','Iowan Old Style',Georgia,serif;
  --sh:0 1px 2px rgba(78,18,40,.05),0 6px 18px -10px rgba(78,18,40,.22);
  --sh2:0 2px 6px rgba(78,18,40,.07),0 18px 40px -18px rgba(78,18,40,.35);
}
body{font-family:var(--ff);color:var(--tx);min-height:100vh;-webkit-font-smoothing:antialiased;
  background:var(--bg);
  /* textura de papel: dois pontinhos muito ténues, nada de imagens */
  background-image:radial-gradient(circle at 1px 1px,rgba(78,18,40,.045) 1px,transparent 0);
  background-size:22px 22px}

/* ── SPLASH ─────────────────────────────────────────────────────── */
#gl-splash{position:fixed;inset:0;z-index:9999;background:linear-gradient(165deg,#3d0e20 0%,var(--vhd) 45%,var(--vh) 120%);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;transition:opacity .28s ease}
.gl-splash-logo{width:76px;height:76px;filter:drop-shadow(0 3px 10px rgba(0,0,0,.35))}
.gl-splash-title{font-family:var(--fd);font-weight:600;font-size:30px;letter-spacing:.5px;color:#fff}
.gl-spin{width:26px;height:26px;border:3px solid rgba(255,255,255,.28);border-top-color:#fff;border-radius:50%;animation:sp .8s linear infinite}
@keyframes sp{to{transform:rotate(360deg)}}

/* ── AUTENTICAÇÃO ───────────────────────────────────────────────── */
.auth-page{display:none;position:fixed;inset:0;z-index:9000;background:var(--bg);overflow-y:auto;
  flex-direction:column;align-items:center;justify-content:center;padding:28px 20px}
.auth-page h2{font-family:var(--fd);font-weight:600;font-size:36px;letter-spacing:.2px;color:var(--vh)}
.auth-faixa{width:64px;height:3px;border-radius:99px;background:linear-gradient(90deg,var(--vh),var(--ou));margin:10px 0 14px}
.auth-sub{font-size:13px;color:var(--mu);text-align:center;max-width:340px;line-height:1.6;margin-bottom:20px}
.auth-card{background:var(--card);border:1px solid var(--bo);border-radius:var(--r2);padding:22px;width:100%;max-width:380px;box-shadow:var(--sh)}
.auth-card label{display:block;font-size:10.5px;font-weight:600;letter-spacing:.7px;text-transform:uppercase;color:var(--mu);margin:14px 0 5px}
.auth-card input{width:100%;padding:11px 13px;border:1px solid var(--bo);border-radius:10px;font-size:15px;font-family:inherit;background:var(--bg)}
.auth-card input:focus{outline:none;border-color:var(--vh);background:#fff;box-shadow:0 0 0 3px var(--vhp)}
.auth-btn{width:100%;padding:12px;border-radius:10px;border:1px solid var(--bo);background:#fff;font-family:inherit;font-size:14px;
  font-weight:600;cursor:pointer;margin-top:12px;display:flex;align-items:center;justify-content:center;gap:9px;transition:all .15s}
.auth-btn.prim{background:var(--vh);color:#fff;border-color:var(--vh);box-shadow:0 6px 16px -8px rgba(123,31,61,.8)}
.auth-btn.prim:hover{background:var(--vh2)}
.auth-btn.ghost:hover{background:var(--vhp)}
.auth-btn.link{border:none;background:none;color:var(--mu);font-weight:500;font-size:12.5px;text-decoration:underline;margin-top:8px}
.auth-btn.google:hover{background:#f7f7f7}
.auth-divider{text-align:center;font-size:11px;color:var(--mu);margin:16px 0 2px;position:relative}
.auth-divider::before,.auth-divider::after{content:'';position:absolute;top:50%;width:33%;height:1px;background:var(--bo)}
.auth-divider::before{left:0}.auth-divider::after{right:0}
.auth-status{font-size:12.5px;margin-top:12px;line-height:1.5;text-align:center;color:var(--mu)}

/* ── HEADER ─────────────────────────────────────────────────────── */
/* `body>header` e não `header`: o mapa dos locais também usa cabeçalhos
   dentro dos cartões, e com o seletor solto herdavam daqui o bordô, o
   sticky e o texto branco — o nome do local ficava branco sobre branco. */
body>header{background:linear-gradient(160deg,#3d0e20 0%,var(--vhd) 50%,#8d2748 130%);color:#fff;position:sticky;top:0;z-index:100;
  box-shadow:0 2px 20px rgba(43,10,22,.28)}
body>header::after{content:'';position:absolute;left:0;right:0;bottom:0;height:2px;
  background:linear-gradient(90deg,transparent,var(--ou),transparent);opacity:.75}
.hdr{max-width:1040px;margin:0 auto;padding:11px 18px;display:flex;align-items:center;justify-content:space-between;gap:12px}
.brand{display:flex;align-items:center;gap:11px;min-width:0}
.escudo{width:34px;height:34px;flex-shrink:0;filter:drop-shadow(0 2px 4px rgba(0,0,0,.35))}
.escudo img{width:100%;height:100%;object-fit:contain;display:block}
.brand h1{font-family:var(--fd);font-weight:600;font-size:22px;letter-spacing:.3px;line-height:1.1;white-space:nowrap}
.brand p{font-size:11px;opacity:.72;font-weight:300;margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.escudo img{border-radius:8px}

/* ── LAYOUT ─────────────────────────────────────────────────────── */
.wrap{max-width:1040px;margin:0 auto;padding:18px 18px 96px}
.sec{display:none}.sec.on{display:block;animation:fadeup .22s ease both}
@keyframes fadeup{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}
.itabs{position:sticky;top:57px;z-index:80;display:flex;gap:3px;margin-bottom:18px;background:var(--bg2);padding:4px;
  border-radius:99px;overflow-x:auto;scrollbar-width:none;box-shadow:0 0 0 18px var(--bg),inset 0 1px 2px rgba(78,18,40,.06)}
.itabs::-webkit-scrollbar{display:none}
.it{background:none;border:none;padding:8px 12px;font-size:12.5px;font-family:inherit;cursor:pointer;color:var(--mu);
  border-radius:99px;transition:all .18s;font-weight:500;white-space:nowrap;flex:1 1 auto;min-width:0}
.it.so-ic{flex:0 0 auto;padding:8px 11px;font-size:14px;line-height:1}
.it:hover{color:var(--tx);background:rgba(255,255,255,.7)}
.it.on{color:#fff;background:var(--vh);font-weight:600;box-shadow:0 4px 12px -4px rgba(123,31,61,.8)}
@media(max-width:520px){.it{padding:7px 7px;font-size:11.5px}}
/* Em ecrã estreito o ícone sai e fica o nome: era o emoji + o nome juntos
   que faziam a barra ir a scroll horizontal. */
@media(max-width:460px){.it .ic{display:none}.it{padding:7px 6px;font-size:11px}}
.note{font-size:12px;color:var(--mu);line-height:1.65}

/* ── STAT CARDS ─────────────────────────────────────────────────── */
.g4{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:11px;margin-bottom:18px}
.sc{background:var(--card);border:1px solid var(--bo);border-radius:var(--r);padding:14px 16px;position:relative;
  overflow:hidden;box-shadow:var(--sh)}
.sc::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--vh)}
.sc.co::before{background:var(--ou)}.sc.cb::before{background:var(--in)}.sc.cv::before{background:var(--vd)}
.sc-l{font-size:10px;font-weight:600;letter-spacing:.9px;text-transform:uppercase;color:var(--mu);margin-bottom:5px}
.sc-v{font-family:var(--fd);font-weight:600;font-size:34px;line-height:1;color:var(--vh);font-variant-numeric:lining-nums}
/* O valor da garrafeira pode ir aos milhares — aos 34px rebentava o card. */
.sc-eur{font-size:27px;overflow-wrap:anywhere}
.sc-s{font-size:11px;color:var(--mu);margin-top:4px;line-height:1.4}

/* Os dois cards DOURADOS — "Região preferida" / "Casta preferida". Dourado
   é a cor da distinção nesta app (menção, nota do Vivino); aqui marca o
   topo, não um número qualquer. Tocam no mesmo painel do card de regiões/
   castas, já aberto na linha certa. */
.sc.sc-fav{cursor:pointer;-webkit-tap-highlight-color:transparent;background:linear-gradient(180deg,#fff,var(--oup));
  border-color:var(--ou);transition:transform .12s,box-shadow .18s}
.sc.sc-fav::before{background:var(--ou)}
.sc.sc-fav:hover{box-shadow:var(--sh2)}
.sc.sc-fav:active{transform:scale(.985)}
.sc-fav-nome{font-family:var(--fd);font-weight:600;font-size:22px;line-height:1.15;color:var(--ou2)}

/* ── RESUMO: cards que abrem ──────────────────────────────────────
   O que mudou: o "voltar" deixou de ser um link solto no meio do painel.
   O painel abre com uma barra própria (migalha + ✕ + ‹ voltar) e liga-se
   ao card por um bico; o card aberto fica preenchido. Continua a ocupar a
   linha toda da grelha (`grid-column:1/-1`) — pô-lo a seguir ao card
   partia a grelha ao meio. */
.sc-click{cursor:pointer;-webkit-tap-highlight-color:transparent;transition:transform .12s,box-shadow .18s,border-color .18s}
.sc-click:hover{box-shadow:var(--sh2)}
.sc-click:active{transform:scale(.985)}
.sc-click.open{border-color:var(--vh);background:linear-gradient(180deg,#fff,var(--vhp))}
.sc-chev{position:absolute;top:11px;right:12px;width:20px;height:20px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;font-size:9px;line-height:1;color:var(--mu);background:var(--bg2);transition:transform .22s,background .18s,color .18s}
.sc-click.open .sc-chev{transform:rotate(180deg);background:var(--vh);color:#fff}
.sc-det{grid-column:1/-1;background:var(--card);border:1px solid var(--vh);border-radius:var(--r);padding:0;
  box-shadow:var(--sh2);overflow:hidden;animation:abrir .2s ease both}
@keyframes abrir{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
.rdet-bar{display:flex;align-items:center;gap:10px;padding:11px 14px;background:linear-gradient(180deg,var(--vhp),#fff);
  border-bottom:1px solid var(--bo)}
.rdet-cab{flex:1;min-width:0;font-size:10.5px;font-weight:600;letter-spacing:.9px;text-transform:uppercase;color:var(--vh);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rdet-cab i{font-style:normal;color:var(--mu);opacity:.8}
@media(max-width:440px){.rdet-cab i{display:none}}   /* em ecrã estreito a migalha vale mais que a contagem */
.rdet-back,.rdet-x{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--bo2);background:#fff;color:var(--vh);
  font-family:inherit;font-size:11.5px;font-weight:600;padding:5px 11px;border-radius:99px;cursor:pointer;transition:all .15s;flex-shrink:0}
.rdet-back:hover,.rdet-x:hover{background:var(--vh);color:#fff;border-color:var(--vh)}
.rdet-x{padding:5px 9px;color:var(--mu)}
.rdet-nota{padding:10px 14px 0;font-size:11.5px;color:var(--mu);line-height:1.5}
.rdet-nota b{color:var(--vh)}
.rdet-rows{padding:4px 14px 8px}
.rdet-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 2px;border-bottom:1px solid var(--bo);
  cursor:pointer;font-size:13.5px;transition:padding-left .15s,background .13s;-webkit-tap-highlight-color:transparent}
.rdet-row:last-child{border-bottom:none}
.rdet-row:hover{background:var(--vhp);padding-left:8px}
.rdet-row>span:first-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rdet-n{font-family:var(--fd);font-weight:600;font-size:13px;color:var(--vh);background:var(--vhp);padding:1px 10px;
  border-radius:99px;flex-shrink:0;border:1px solid #f0dbe2}
.rdet-tit{display:none}
.rdet-lista{padding:12px 14px 4px;background:var(--bg);border-top:1px solid var(--bo)}
.rdet-lista .vcard:last-child{margin-bottom:10px}
.rdet-lista .vcard{box-shadow:none}

/* ── DETALHE (organizado por região/ano) ────────────────────────── */
/* A barra da lista NÃO é um cartão. Era — e com a procura a passar para
   cima dela ficavam dois cartões encostados, que se liam como dois painéis
   quando isto é só a legenda da lista que vem a seguir. Sem moldura, a
   contagem e os comandos ficam a flutuar sobre o papel e o cartão que se vê
   é o da procura, que é o que se usa. Mesmo desenho da `.cat-barra` do
   Catálogo da WineCatalog. */
/* NOWRAP, e é o ponto todo. Com `flex-wrap`, a decisão de quebrar a linha
   é tomada pela largura de CONTEÚDO de cada item — o `min-width:0` da
   contagem não a evitava — e por isso a barra tinha duas alturas: uma com
   "8 vinhos" e outra com "170 vinhos · 210 garrafas", que empurrava a
   ordenação e a vista para baixo. Sem quebra, a barra tem sempre a mesma
   altura: o que cede é o TEXTO, que é o que se pode encolher. */
.dbar{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:nowrap;
  margin:0 2px 14px}
/* Quando a linha quebra (telemóvel), um item sozinho com `space-between`
   encosta à ESQUERDA — e os comandos ficavam a boiar por baixo da
   contagem, desalinhados de tudo. Com `margin-left:auto` mantêm-se à
   direita nas duas larguras, que é onde o olho os vai procurar. */
.dbar-a{margin-left:auto;display:flex;align-items:center;gap:7px;flex-shrink:0}
/* A contagem à ESQUERDA: é o primeiro número que se lê ao entrar aqui, e
   ficava encostado às setas do agrupamento do lado direito. */
/* A contagem CEDE, os comandos não se mexem. `min-width:0` + reticências
   faz com que a contribuição dela para a largura mínima da linha seja ZERO
   — e é isso que a impede de empurrar os comandos para a linha de baixo
   quando os números crescem. "100 vinhos · 210 garrafas" quebrava a barra
   em duas linhas e "8 vinhos · 9 garrafas" não: a barra mudava de altura
   conforme o filtro, que é o pior dos dois mundos. Agora a barra tem
   sempre a mesma altura e o que encolhe é o texto — pelo FIM, que é onde
   está o menos importante; o número vem à frente e nunca se perde. */
.dbar .fcount{text-align:left;flex:1 1 auto;min-width:0;font-size:10.5px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* No telemóvel só o número dos VINHOS — é o que a lista a seguir mostra, e
   é o que faz a barra caber ao lado dos comandos sem reticências. As
   garrafas não se perdem: estão no painel da procura, aqui mesmo por cima.
   (Reticências ficam como rede: com um número absurdo, corta-se pelo fim,
   que é onde está o menos importante — o número vem à frente.) */
@media(max-width:560px){.det-gar{display:none}}
/* Os grupos de botões ganham o fundo de CARTÃO que a barra perdeu: sem
   moldura por baixo, um botão em tom de papel sobre papel deixava de se ler
   como um comando. */
.segbtns{display:flex;align-items:center;border:1px solid var(--bo);border-radius:99px;
  overflow:hidden;flex-shrink:0;background:var(--card)}
/* A marca do que os três botões a seguir fazem: arrumam a lista. Sem ela
   "Região · Ano · Casta" lê-se como mais um filtro, logo por baixo dos
   filtros a sério. Não é botão — não há ascendente/descendente para
   trocar; a ordem DENTRO de cada grupo é sempre a nota do Vivino. */
/* O ⇅ vive FORA da pílula, colado a ela. Dentro, ocupava uma célula
   branca do mesmo tamanho dos botões e lia-se como um quarto botão —
   apagado, que é o pior dos dois mundos. Fora, é uma etiqueta. */
.segico{font-size:12px;color:var(--mu);line-height:1;user-select:none;flex-shrink:0;opacity:.75}
.segbtn{padding:6px 11px;font-size:11.5px;font-family:inherit;border:none;background:none;color:var(--mu);cursor:pointer;font-weight:600;transition:all .15s}
.segbtn.on{background:var(--vh);color:#fff}
/* Os dois botões da vista são ícones: mais estreitos, e uma barra que já
   tem a contagem e três botões de agrupamento não aguenta mais duas
   palavras sem partir numa terceira linha no telemóvel. */
.segbtn.ico{padding:6px 10px;font-size:13px;line-height:1}
.dgrupo{margin-bottom:22px}
.dgrupo-tit{font-family:var(--fd);font-weight:600;font-size:16px;letter-spacing:.2px;color:var(--vhd);
  display:flex;align-items:center;gap:9px;padding-bottom:7px;margin-bottom:11px;position:relative}
.dgrupo-tit::after{content:'';position:absolute;left:0;right:0;bottom:0;height:1px;
  background:linear-gradient(90deg,var(--vh),transparent 65%);opacity:.4}
.dgrupo-n{font-family:var(--ff);font-size:10.5px;font-weight:600;color:var(--mu);background:var(--bg2);padding:2px 9px;
  border-radius:99px;letter-spacing:.3px}

/* ── CARTÃO DE VINHO ──────────────────────────────────────────────
   Três zonas, sempre pela mesma ordem: a GARRAFA (imagem, com a
   quantidade em cima), a IDENTIDADE (nome, ano, produtor/região, castas e
   menção) e, depois de um filete, o RODAPÉ do que é físico — onde está,
   maturação, nota. Antes os crachás vinham todos no mesmo monte e cada um
   com a sua cor; agora a posição diz o que a coisa é. */
.vcard{background:var(--card);border:1px solid var(--bo);border-radius:var(--r);padding:12px 14px;margin-bottom:10px;
  cursor:pointer;transition:box-shadow .18s,transform .1s,border-color .18s;-webkit-tap-highlight-color:transparent;box-shadow:var(--sh)}
.vcard:hover{box-shadow:var(--sh2);border-color:var(--bo2)}
.vcard:active{transform:scale(.995)}
.vc-top{display:flex;align-items:stretch;gap:13px}
.vc-thumb{position:relative;width:52px;flex-shrink:0;border-radius:10px;background:
  linear-gradient(160deg,#fff,var(--bg2));border:1px solid var(--bo);display:flex;align-items:center;justify-content:center;
  padding:5px 3px;overflow:hidden}
.vc-thumb svg{display:block;width:100%;height:auto;max-height:74px;filter:drop-shadow(0 2px 3px rgba(43,10,22,.18))}
.vc-thumb img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.vc-qtd{position:absolute;top:-1px;right:-1px;background:var(--vh);color:#fff;font-size:10px;font-weight:700;
  padding:2px 6px;border-radius:0 9px 0 9px;letter-spacing:.2px}
/* `flow-root`, não `flex`: um item de flex ignora `float` (spec do CSS), e
   é o float do `.vc-anofloat` que deixa o nome subir para o lado do
   ano+nota em vez de esperar por ele — ver o comentário de vinhoCardHTML
   em app.js. `flow-root` só garante que este contentor cresce para incluir
   o float (senão, com um nome curto, o float podia sair por baixo do
   cartão) sem cortar nada, ao contrário de `overflow:hidden`. */
.vc-main{flex:1;min-width:0;display:flow-root}
.vc-anofloat{float:right;display:flex;flex-direction:column;align-items:flex-end;gap:3px;margin-left:10px}
.vc-anofloat .bdg{font-size:9px;padding:2px 8px}
.vc-nome{font-family:var(--fd);font-weight:600;font-size:16px;line-height:1.3;letter-spacing:.1px;color:var(--tx)}
.vc-ano{font-family:var(--fd);font-weight:400;font-size:19px;color:var(--vh);line-height:1;
  font-variant-numeric:lining-nums;opacity:.9}
.vc-sub{font-size:11.5px;color:var(--mu);margin-top:3px;line-height:1.45}
.vc-badges:empty{display:none}
.vc-badges{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px;align-items:center}
.vc-foot{display:flex;flex-wrap:wrap;gap:5px 10px;align-items:center;margin-top:9px;padding-top:8px;border-top:1px dashed var(--bo)}
.vc-foot:empty{display:none}
.vc-l{display:inline-flex;align-items:center;gap:5px;font-size:11px;color:var(--mu);min-width:0}
.vc-l b{font-weight:500;color:var(--tx);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.vc-pip{width:7px;height:7px;border-radius:50%;flex-shrink:0;box-shadow:0 0 0 2px #fff,0 0 0 3px rgba(0,0,0,.06)}

/* Onde é que a palavra estava (só enquanto se procura por texto).
   Faixa colada ao fundo do cartão, a sangrar até às bordas (as margens
   negativas são o padding do .vcard ao contrário) e em tom de papel um
   pouco mais escuro: lê-se como um rodapé da PROCURA, não como mais uma
   linha da ficha do vinho — daí ficar fora do .vc-top, a toda a largura,
   e não alinhada com a coluna do nome.
   A palavra encontrada leva bordô e não dourado: o dourado é a distinção
   (menção, nota do Vivino) e uma palavra sombreada não distingue vinho
   nenhum — é a app a apontar para o que lhe perguntaram. */
.vc-match{margin:11px -14px -12px;padding:8px 14px 9px;border-top:1px solid var(--bo);
  background:var(--bg);border-radius:0 0 13px 13px}
.vcm-l{display:flex;gap:9px;align-items:baseline;font-size:11px;line-height:1.5;color:var(--mu)}
.vcm-l+.vcm-l{margin-top:5px}
.vcm-k{flex:0 0 auto;font-size:9px;letter-spacing:.5px;text-transform:uppercase;font-weight:700;
  color:var(--vh);opacity:.8}
/* Duas linhas chegam: o que se quer ver é a palavra e o que ela tem à
   volta — a nota de prova inteira lê-se na ficha do vinho. */
.vcm-t{min-width:0;flex:1;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
mark.hl{background:rgba(123,31,61,.13);color:var(--vhd);font-weight:600;border-radius:3px;padding:0 2px}

/* ── CARTÃO DE GRELHA ─────────────────────────────────────────────
   A outra vista do Detalhe (`vinhoGrelhaHTML`). A garrafa manda: é a
   largura toda do cartão, com o resto por baixo e centrado. Não é o
   cartão da lista mais pequeno — é a mesma informação reduzida ao que
   identifica um rótulo de longe.
   `auto-fill` com `minmax(150px,1fr)` e não um número fixo de colunas:
   num telemóvel dá duas, num ecrã largo dá as que couberem, sem um
   `@media` a decidir por nós. */
.vgrelha{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px;align-items:start}
.vgcard{background:var(--card);border:1px solid var(--bo);border-radius:var(--r);padding:12px 12px 11px;
  cursor:pointer;transition:box-shadow .18s,transform .1s,border-color .18s;-webkit-tap-highlight-color:transparent;
  box-shadow:var(--sh);display:flex;flex-direction:column;align-items:center;text-align:center;min-width:0}
.vgcard:hover{box-shadow:var(--sh2);border-color:var(--bo2)}
.vgcard:active{transform:scale(.995)}
/* A mesma moldura da lista, maior e com a proporção de uma garrafa. A
   thumb é `width:52px` na lista — aqui passa a ocupar a coluna. */
/* A garrafa toma a largura do cartão, mas NÃO cresce sem fim: num ecrã
   largo (1040px de `.wrap`, quatro ou cinco colunas) sem o tecto ficava
   um poster por vinho, e o que a grelha tem de dar é MUITOS rótulos de uma
   vez — é essa a diferença para a lista. O `max-width` não chega a apertar
   num telemóvel, onde as duas colunas já dão ~128px.
   O `viewBox` da garrafa é 40×74 (mais alta do que larga) e a moldura é
   3/4: com o `width:100%` da lista, a garrafa saía por baixo e ficava
   cortada. Aqui é a ALTURA que manda e a largura vem atrás. */
.vgcard .vc-thumb{width:100%;max-width:136px;margin:0 auto;aspect-ratio:3/4;padding:8px 6px}
.vgcard .vc-thumb svg{width:auto;height:100%;max-height:none;max-width:100%}
.vg-nome{font-family:var(--fd);font-weight:600;font-size:14px;line-height:1.3;color:var(--tx);margin-top:10px;
  overflow-wrap:anywhere}
.vg-sub{font-size:10.5px;color:var(--mu);margin-top:3px;line-height:1.4;overflow-wrap:anywhere}
.vg-foot{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:5px 8px;margin-top:8px;width:100%}
.vg-foot:empty{display:none}
.vg-foot .vc-l{max-width:100%}
.vg-mais{font-style:normal;font-size:10px;color:var(--mu)}
/* A faixa da procura sangra até às bordas do cartão como na lista — as
   margens negativas são o padding do `.vgcard` ao contrário, e por isso
   são outras. O que MUDA aqui é a linha: na lista o nome do campo fica à
   esquerda e o trecho ao lado; numa coluna de 150px isso deixava
   "HARMONIZA COM" a comer a largura toda e sobrava "… pratos" para o
   texto, que é precisamente a palavra que a faixa existe para mostrar.
   Empilhado, o trecho fica com a largura inteira do cartão. */
.vgcard .vc-match{width:calc(100% + 24px);margin:10px -12px -11px;padding:7px 11px 8px;text-align:left}
.vgcard .vcm-l{display:block}
.vgcard .vcm-k{display:block;margin-bottom:1px}

/* Crachás: um só desenho. A cor é excepção, não regra —
   dourado = distinção (menção/nota), o resto vive em tons de papel. */
.bdg{display:inline-flex;align-items:center;gap:4px;font-size:10.5px;padding:3px 9px;border-radius:99px;
  background:var(--bg);color:var(--mu);border:1px solid var(--bo);white-space:nowrap;line-height:1.5}
.bdg.cas{background:#f7f3f8;color:#5c4166;border-color:#e9dfec}
.bdg.mono{background:transparent;color:var(--mu);border-color:var(--bo2);border-style:dashed;
  font-size:9.5px;letter-spacing:.6px;text-transform:uppercase;font-weight:600}
.bdg.men,.bdg.viv{background:var(--oup);color:var(--ou2);border-color:#eddfba;font-weight:600}
.bdg.viv{background:#fff;border-color:#e6d7ad}
.bdg.loc{background:var(--inp);color:var(--in);border-color:#d7e4f0}
.bdg.reg{background:var(--vhp);color:var(--vh);border-color:#f0dbe2}
.bdg.qtd{background:var(--vh);color:#fff;border-color:var(--vh);font-weight:600}
.bdg.jan{background:#fff;border-color:var(--bo2)}
.bdg.jan.ponto{background:var(--vdp);color:var(--vd);border-color:#cfe3d8}
.bdg.jan.cedo{background:var(--bg2);color:var(--mu)}
.bdg.jan.passou{background:var(--dgp);color:var(--dg);border-color:#f2cdcb}
/* "No ponto" está em quase todos os vinhos e por isso já não separava
   nada. O crachá passa a ENCHER-SE até ao ano em que estamos dentro da
   janela (`--p`: 0 no primeiro ano, 1 no último) e o rebordo do
   enchimento — os últimos 2px, mais escuros — é o marcador. A informação
   entra DENTRO do que já lá estava: o cartão não ganha linha nem crachá
   novo, e o rodapé não alarga um pixel.
   O verde é o `--vd` em rgba e não passa de .14 por cima do texto: mais
   do que isso e o próprio texto do crachá deixava de se ler. Vai em
   ::before com `z-index:-1` para ficar POR BAIXO do texto, e o
   `isolation:isolate` prende esse z-index negativo ao crachá — sem ele o
   preenchimento descia para trás do cartão e desaparecia.
   Em `--p:0` não se pinta nada, e é o que se quer dizer: a janela abriu
   este ano, ainda não se gastou nada dela. */
.bdg.jan.cheio{position:relative;overflow:hidden;isolation:isolate}
.bdg.jan.cheio::before{content:'';position:absolute;left:0;top:0;bottom:0;z-index:-1;
  width:calc(var(--p) * 100%);
  background:linear-gradient(90deg,rgba(61,107,82,.07),rgba(61,107,82,.14) calc(100% - 2px),
    rgba(61,107,82,.45) calc(100% - 2px))}
.vazio{text-align:center;padding:38px 18px;color:var(--mu);font-size:13px;line-height:1.7;
  background:var(--card);border:1px dashed var(--bo2);border-radius:var(--r)}
.vazio b{font-family:var(--fd);font-weight:600;display:block;font-size:16px;color:var(--vh);margin-bottom:6px}

/* ── PESQUISA ─────────────────────────────────────────────────────
   Uma barra de procura e mais nada à vista: os filtros vivem atrás do
   botão "Filtros", que traz o número dos que estão ligados. Assim o ecrã
   inicial não abre com nove caixas cinzentas. Cada filtro é um chip
   desenhado com o <select> nativo por cima, invisível — o desenho é
   nosso, o seletor continua a ser o do telemóvel. */
/* O topo do separador tem três coisas empilhadas — separadores, procura,
   barra da lista — e o que as separa é o FEITIO e o PESO, não a cor:
   os separadores são uma pílula em tom de papel (`--bg2`), a procura é um
   cartão branco, a barra não tem moldura nenhuma. Antes eram três lozangos
   brancos do mesmo tamanho e nenhum mandava.
   **A SOMBRA fica.** Tirá-la foi uma tentativa de aliviar o topo e deu
   nisto: `--card` (#fffdfb) sobre `--bg` (#f6f1ea) com um bordo `--bo` é
   diferença a menos — a barra desaparecia no papel e o ecrã abria com a
   contagem colada aos separadores. É a sombra que a põe à tona. */
.filtros{background:var(--card);border:1px solid var(--bo);border-radius:var(--r);
  padding:11px 12px;margin-bottom:14px;box-shadow:var(--sh)}
/* Fechada é só ESTA linha: a caixa de texto a ocupar o espaço todo e, fixo
   à direita, o botão que abre a fita dos campos. */
.fsearch{display:flex;align-items:center;gap:8px}
.fsearch-box{position:relative;flex:1;min-width:0;display:flex;align-items:center}
.fsearch-i{position:absolute;left:13px;font-size:14px;opacity:.55;pointer-events:none;line-height:1}
.filtros input[type=search]{width:100%;padding:12px 38px 12px 38px;border:1px solid var(--bo);border-radius:99px;font-size:13px;
  font-family:inherit;background:var(--bg);-webkit-appearance:none;transition:all .18s}
.filtros input[type=search]::-webkit-search-cancel-button{display:none}
.filtros input[type=search]:focus{outline:none;border-color:var(--vh);background:#fff;box-shadow:0 0 0 3px var(--vhp)}
.fsearch-x{position:absolute;right:8px;width:24px;height:24px;border-radius:50%;border:none;background:var(--bg2);color:var(--mu);
  font-size:11px;cursor:pointer;display:none;align-items:center;justify-content:center;font-family:inherit}
.fsearch-x.on{display:flex}
.fbar{display:flex;align-items:center;gap:9px;margin-top:10px;flex-wrap:wrap}
.fcount{font-size:11.5px;color:var(--mu);flex:1;min-width:90px;text-align:right}
/* O botão que abre a fita dos campos, à direita da procura. Traz o número
   dos VALORES ligados — é a única medida, com o painel fechado, do que
   está a cortar a lista por baixo. */
.ftoggle{flex-shrink:0;display:inline-flex;align-items:center;gap:7px;
  border:1px solid var(--bo2);background:var(--bg);color:var(--tx);
  font-family:inherit;font-size:12px;font-weight:600;padding:10px 13px;
  border-radius:99px;cursor:pointer;transition:all .15s}
.ftoggle:hover{border-color:var(--vh);color:var(--vh)}
.ftoggle .fchev{font-size:8px;color:var(--mu);transition:transform .2s}
.filtros.aberto .ftoggle{background:var(--vh);color:#fff;border-color:var(--vh)}
.filtros.aberto .ftoggle .fchev{transform:rotate(180deg);color:#fff}
.filtros.aberto .fn{background:#fff;color:var(--vh)}
.fn{background:var(--vh);color:#fff;font-size:10px;font-weight:700;min-width:17px;height:17px;border-radius:99px;
  display:none;align-items:center;justify-content:center;padding:0 5px}
.fn.on{display:inline-flex}

/* ── O PAINEL: sempre a procura, e os filtros atrás do botão ────────
   Já teve três andares (procura / cor+região+castas / os outros nove) e o
   andar do meio dava meio ecrã de cartões antes de se chegar à lista.
   Agora é a procura sempre à vista e, atrás do botão, uma FITA de uma
   linha com os doze campos — só os valores de UM abrem por baixo. */
.filtros .fcampos,.filtros .fdom,.filtros .fbar{display:none}
.filtros.aberto .fcampos{display:flex;animation:abrir .18s ease both}
.filtros.aberto .fdom:not(:empty){display:block;animation:abrir .18s ease both}
.filtros .fbar.on{display:flex}

/* A FITA. Rola de lado e não quebra: doze campos em `flex-wrap` eram três
   linhas de pastilhas, que é o espaço que isto veio poupar. A barra de
   scroll esconde-se (no telemóvel nem aparece, e no desktop roubava 15px
   de altura a uma linha de 32); `overscroll-behavior-x:contain` impede
   que chegar ao fim da fita puxe a página — ou, no iOS, o gesto de voltar
   atrás. */
.fcampos{gap:6px;overflow-x:auto;overscroll-behavior-x:contain;
  margin-top:11px;padding:11px 0 2px;border-top:1px solid var(--bo);
  scrollbar-width:none;-ms-overflow-style:none}
.fcampos::-webkit-scrollbar{display:none}
.fcampo{flex-shrink:0;display:inline-flex;align-items:center;gap:6px;
  padding:7px 12px;border:1px solid var(--bo);border-radius:99px;background:var(--bg);
  font-family:inherit;font-size:12px;font-weight:600;color:var(--mu);cursor:pointer;
  white-space:nowrap;transition:all .15s}
.fcampo:hover{border-color:var(--bo2);background:#fff}
/* Dois estados e não um: LIGADO (tem valores escolhidos) e ABERTO (é o que
   está a mostrar os valores). São coisas diferentes — pode estar ligado sem
   estar aberto, que é o caso normal — e por isso um é o contorno e o outro
   o preenchimento. */
.fcampo.ativo{border-color:var(--vh);color:var(--vh);background:var(--vhp)}
.fcampo.aberto{background:var(--vh);border-color:var(--vh);color:#fff}
.fcn{font-style:normal;font-size:10px;font-weight:700;min-width:16px;height:16px;
  border-radius:99px;display:inline-flex;align-items:center;justify-content:center;
  padding:0 4px;background:var(--vh);color:#fff}
.fcampo.aberto .fcn{background:rgba(255,255,255,.28)}

.fdom{margin-top:11px}
.fvazio{font-size:11.5px;color:var(--mu);padding:4px 2px}

/* OS VALORES do campo aberto: DUAS por linha, e uma GRELHA — não um
   `flex-wrap`. Com três por linha "Península de Setúbal" e "Cabernet
   Sauvignon" chegam ao ecrã cortadas a meio, e um filtro que não se lê não
   se escolhe; com `flex-grow`, o último cartão de uma linha ímpar
   estica-se sozinho de ponta a ponta. `minmax(0,1fr)` e `min-width:0` no
   cartão porque o mínimo de um item de grelha é `auto`: sem isso é a
   coluna que cresce. */
/* Duas colunas no telemóvel, mais num ecrã largo — `auto-fill` com um
   mínimo de 170px, e não `repeat(2,…)` fixo: com duas colunas fixas, um
   "Alentejo 3" num ecrã de 900px ficava um cartão de 700px de largura com
   duas palavras lá dentro. O mínimo é o que mantém as duas colunas no
   telemóvel (2×150+6 cabe nos ~334px úteis do cartão, 3 não cabem) e é ele que
   impede um cartão estreito de mais para "Península de Setúbal". O
   `minmax(0,…)` continua a ser preciso porque o mínimo de um item de
   grelha é `auto` — ver o `min-width:0` do `.fop`. */
.fops{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(150px,100%),1fr));gap:6px}
.fop{display:flex;align-items:center;justify-content:space-between;gap:6px;min-width:0;
  padding:9px 10px;border-radius:12px;border:1px solid var(--bo);background:var(--bg);color:var(--tx);
  font-family:inherit;font-size:12px;text-align:left;cursor:pointer;transition:all .15s}
.fop:hover{border-color:var(--bo2);background:#fff}
.fop.on{background:var(--vh);border-color:var(--vh);color:#fff}
/* O texto QUEBRA, não corta: com reticências, "Alicante Bousc…" e
   "Alicante Branco" são o mesmo cartão. Numa grelha os dois cartões de uma
   linha têm sempre a mesma altura, por isso duas linhas não desalinham
   nada. `anywhere` para o caso de uma palavra não caber de todo. */
.fop-tx{display:flex;align-items:center;gap:6px;font-weight:600;min-width:0;
  white-space:normal;overflow-wrap:anywhere;line-height:1.25}
.fconta{font-size:10.5px;font-weight:700;color:var(--mu);flex-shrink:0}
.fop.on .fconta{color:rgba(255,255,255,.75)}
.fponto{width:8px;height:8px;border-radius:50%;flex-shrink:0;display:inline-block}
.fop.on .fponto{box-shadow:0 0 0 1.5px rgba(255,255,255,.5)}
/* As duas regras das castas, por cima dos valores. */
.fregras{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-bottom:9px}
/* As pastilhas dizem o que NÃO se vê daqui: o campo aberto já se lê nos
   cartões acesos. Quem decide isso é o `renderFiltros` (ver a regra lá);
   aqui só se esconde a fila vazia. */
.factivos{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.factivos:empty{display:none}
.fpill{display:inline-flex;align-items:center;gap:7px;background:var(--vhp);border:1px solid #f0dbe2;color:var(--vh);
  font-size:11.5px;font-weight:600;padding:4px 6px 4px 11px;border-radius:99px}
.fpill button{border:none;background:rgba(123,31,61,.12);color:var(--vh);width:17px;height:17px;border-radius:50%;
  font-size:10px;cursor:pointer;font-family:inherit;line-height:1}
.fpill button:hover{background:var(--vh);color:#fff}
/* O "+" entre duas pastilhas de casta: só existe em "todas em simultâneo",
   e é o que separa "Touriga OU Syrah" de "Touriga E Syrah" com o painel
   fechado. Não é botão — quem troca a regra é o visto lá dentro. */
.fjunta{align-self:center;font-size:12px;font-weight:700;color:var(--vh);opacity:.6;padding:0 1px}
/* O visto das castas, ao lado do chip. Só aparece com duas escolhidas —
   com uma, "qualquer uma" e "todas" dão a mesma lista. Mesmo desenho (e
   mesmas palavras) do Catálogo da WineCatalog. */
/* Os vistos das castas vivem na `.fregras`, ao lado do título do grupo —
   são REGRAS sobre os cartões de baixo, não mais um filtro. */
.fmodo{display:inline-flex;align-items:center;gap:6px;background:none;border:none;padding:1px 0;
  font-family:inherit;font-size:11px;font-weight:600;color:var(--mu);cursor:pointer;white-space:nowrap}
.fmodo.on{color:var(--vh)}
.fvisto{width:15px;height:15px;border-radius:4px;border:1.5px solid var(--bo2);background:var(--card);
  display:flex;align-items:center;justify-content:center;flex-shrink:0;
  font-size:10px;font-style:normal;font-weight:700;line-height:1;color:transparent}
.fmodo.on .fvisto{background:var(--vh);border-color:var(--vh);color:#fff}
.lnk{background:none;border:none;color:var(--vh);font-size:12px;font-family:inherit;cursor:pointer;text-decoration:underline}
.fbar select{padding:6px 9px;border:1px solid var(--bo);border-radius:8px;font-size:12px;font-family:inherit;background:var(--bg)}

/* ── MAPA DOS LOCAIS ──────────────────────────────────────────────
   UM local de cada vez (`.ml`): barra com ‹ › para os locais vizinhos, o
   nome e a contagem, os pontos de "onde estou", e por baixo as
   prateleiras nível a nível. A madeira em tons de papel, os lugares em
   bordô — nada de imagens. */
.ml{--slot:34px;background:var(--card);border:1px solid var(--bo);border-radius:var(--r2);box-shadow:var(--sh);overflow:hidden;padding-bottom:9px}
.ml-bar{display:flex;align-items:center;gap:4px;padding:6px 8px;position:relative;
  background:linear-gradient(180deg,rgba(255,255,255,.6),transparent),var(--bg);border-bottom:1px solid var(--bo)}
.ml-bar::before{content:'';position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--lc,var(--vh))}
.ml-nav{width:33px;height:33px;border-radius:50%;border:1px solid var(--bo2);background:#fff;color:var(--vh);font-family:var(--fd);
  font-size:24px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;padding:0 0 3px;
  box-shadow:var(--sh);transition:all .15s}
.ml-nav:hover{background:var(--vhp);border-color:var(--vh)}
.ml-nav:active{transform:scale(.94)}
.ml-nav:disabled{opacity:.25;cursor:default;box-shadow:none}
.ml-t{flex:1;min-width:0;text-align:center}
.ml-t h3{font-family:var(--fd);font-weight:600;font-size:17px;letter-spacing:.2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ml-edit{width:24px;height:24px;margin-left:4px;border-radius:50%;border:none;background:none;color:var(--vh);font-family:inherit;
  font-size:13px;line-height:1;cursor:pointer;vertical-align:middle;opacity:.7}
.ml-edit:hover{background:var(--vhp);opacity:1}
.ml-sub{font-family:var(--fd);font-size:12.5px;color:var(--mu);margin-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ml-sub b{font-weight:600;color:var(--vh);font-variant-numeric:lining-nums}
.ml-sub i{font-style:normal;font-family:var(--ff);font-size:11px}
.ml-dots{display:flex;justify-content:center;gap:6px;padding:6px 0 0}
.ml-dot{width:7px;height:7px;border-radius:99px;border:none;background:var(--bo2);padding:0;cursor:pointer;transition:all .18s}
.ml-dot.on{background:var(--vh);width:18px}
.ml-nota{padding:10px 14px 0}
.ml-vazio{padding:26px 18px 14px}
.ml-leg{display:flex;flex-wrap:wrap;gap:4px 16px;justify-content:center;padding:9px 12px 0;font-size:10px;color:var(--mu)}
.ml-leg span{display:inline-flex;align-items:center;gap:6px}
.ml-leg i{width:13px;height:13px;border-radius:50%;flex-shrink:0;display:inline-block}
.ml-leg .cheia{background:var(--vh)}
.ml-leg .vazia{border:1.5px dashed #c9a1af}
/* As garrafas por posicionar vivem FORA do cartão e fechadas: são uma
   lista que pode ter dezenas de linhas e aberta empurrava a estante para
   fora do ecrã. */
.ml-extras{margin-top:9px;background:var(--card);border:1px solid var(--bo);border-radius:var(--r);box-shadow:var(--sh);
  padding:0 14px;overflow:hidden}
.ml-extras>summary{padding:11px 0;font-size:12.5px;color:var(--mu);cursor:pointer;list-style:none;
  display:flex;align-items:center;gap:7px;-webkit-tap-highlight-color:transparent}
.ml-extras>summary::-webkit-details-marker{display:none}
.ml-extras>summary::after{content:'▾';margin-left:auto;font-size:10px;color:var(--vh);transition:transform .2s}
.ml-extras[open]>summary::after{transform:rotate(180deg)}
.ml-extras>summary b{font-family:var(--fd);font-size:15px;font-weight:600;color:var(--vh);font-variant-numeric:lining-nums}
.ml-extras .note{margin-bottom:9px}
.ml-extras .mgrid{padding-bottom:13px}
.ml-add{margin-top:7px;text-align:center}
.ml-add .btn{margin-top:0}
.vazio .ro-hide{margin-top:12px}
.mprat{padding:0 12px;margin-top:12px}
/* Uma prateleira é UMA LINHA: o nome à esquerda, a estante no meio, a
   contagem à direita. O nome já teve linha própria por cima (com o
   filete a atravessar) e custava ~24px por nível — em oito níveis, um
   terço da altura do ecrã gasto em rótulos. */
.mprat-layout{display:flex;align-items:center;gap:7px;padding:0 12px;margin-top:calc(var(--slot,34px) * .14);
  /* num ecrã largo a linha não se estica até ao infinito: o nome do nível
     ficava a meio metro da estante, um em cada canto do cartão */
  max-width:680px;margin-left:auto;margin-right:auto}
/* O nome do nível fica ENCOSTADO À ESQUERDA e a estante ao meio: o que os
   liga é um fio tracejado, como numa legenda de planta. Antes a linha
   encolhia ao conteúdo e o nome andava colado à estante — mudava de sítio
   de nível para nível, conforme a prateleira era mais larga ou mais
   estreita, e a coluna dos nomes deixava de se ler de uma vez. */
.mp-lbl{flex:0 0 auto;max-width:84px;font-size:8.5px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;
  color:var(--mu);line-height:1.25;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow-wrap:anywhere}
/* O fio é só uma AJUDA a ver onde está cada nível: vai do nome até onde
   a prateleira começa e mais nada. Muito leve e tracejado de propósito —
   não é desenho da estante, e um traço a sério lia-se como uma peça do
   móvel. Do lado direito não há nenhum: a linha que ia dali até ao
   contador atravessava a estante toda e era ela que se via, em vez dos
   berços. */
.mp-fio{flex:1 1 6px;min-width:4px;height:0;border-bottom:1px dashed var(--bo2);opacity:.3}
/* Do outro lado não há fio nenhum — há um espaçador do mesmo tamanho, que
   é o que mantém a estante CENTRADA na linha depois de o contador sair.
   Sem ele, o `flex:1` do fio empurrava a prateleira toda para a direita. */
.mp-esp{flex:1 1 6px;min-width:4px}
.mprat-t{display:flex;align-items:center;gap:9px;font-size:10.5px;font-weight:600;letter-spacing:.9px;text-transform:uppercase;
  color:var(--mu);margin-bottom:8px}
.mprat-t::after{content:'';flex:1;height:1px;background:var(--bo)}
.mprat-n{font-family:var(--fd);font-size:13px;font-weight:600;letter-spacing:0;text-transform:none;color:var(--vh);flex-shrink:0;order:3;font-variant-numeric:lining-nums}
.mgrid{display:grid;grid-template-columns:1fr;gap:7px}
.mcell{display:flex;align-items:center;gap:8px;background:var(--bg);border:1px solid var(--bo);border-radius:10px;
  padding:7px 9px;cursor:pointer;font-size:11.5px;line-height:1.35;text-align:left;font-family:inherit;
  transition:all .15s;-webkit-tap-highlight-color:transparent;min-width:0}
.mcell:hover{background:#fff;border-color:var(--vh);box-shadow:var(--sh);transform:translateY(-1px)}
.mcell svg{flex-shrink:0;display:block;width:15px;height:auto}
.mcell-tx{min-width:0;flex:1;display:flex;align-items:baseline;gap:7px;overflow:hidden}
.mcell-tx b{font-family:var(--fd);font-weight:600;font-size:13px;color:var(--tx);letter-spacing:.2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.mcell-tx span{flex-shrink:0;color:var(--mu);font-size:10.5px;white-space:nowrap}
.mlug{font-size:9.5px;font-weight:700;color:var(--vh);background:var(--vhp);border-radius:5px;padding:1px 5px;
  flex-shrink:0;letter-spacing:.3px}
/* A prateleira em HTML (`estanteHTML`): a grelha põe cada lugar na sua
   coluna/fila e o formato dá a madeira — barra (fila), bloco
   (sobrepostos) ou a fita em ziguezague, que é um SVG esticado à caixa
   por trás dos lugares. A grelha do ziguezague NÃO tem gap de propósito:
   é o que deixa a fita passar exatamente pelo centro de cada lugar (ver
   `ziguezagueBgSVG`). O espaço entre lugares vem da margem de cada um.

   **`--slot` (o tamanho de um lugar) vem do JS, não daqui**
   (`ajustarEstantes`): é ele que faz a estante inteira caber no ecrã sem
   scroll, e o valor depende de quantos níveis a pessoa tem. Tudo o que
   mede alguma coisa aqui sai dele — o espaço entre lugares, o padding da
   madeira, o corpo do número. Um `56px` fixo cabia numa garrafeira de
   três níveis e obrigava a rolar meia página numa de oito. */
.est-wrap{flex:0 1 auto;min-width:0;overflow-x:auto;margin:0 11px}
.est{--colw:calc(var(--slot) * var(--colr,1.5));position:relative;display:grid;
  grid-template-columns:repeat(var(--gcols,var(--cols)),calc(var(--colw) / 2));
  grid-template-rows:repeat(var(--rows),auto);align-items:center;
  /* A caixa é a largura do MÓVEL — o nível mais largo, mais uma coluna de
     folga (`--colsw`, ver `layoutLocal`) — e é igual em todas as
     prateleiras do local. Antes cada uma valia o que os seus lugares
     mediam, e uma estante de 4/3/4/3 lia-se como uma pilha de tábuas
     irregulares em vez de um móvel; a folga é o que deixa uma prateleira
     desviar-se meia coluna sem sair da caixa. O espaço entre lugares vem
     da margem de cada um e não de um `gap`, para a coluna medir sempre o
     mesmo e os vales da onda caírem debaixo dos lugares. */
  width:calc(var(--colsw,var(--cols)) * var(--colw));margin:0 auto}
.est-fila,.est-sobrepostos{padding:calc(var(--slot) * .16 + 2px) 0;border-radius:calc(var(--slot) * .38);
  border:1px solid #dccbb0;background:linear-gradient(180deg,#f4ecdf,#e8dbc5);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.75),inset 0 -2px 0 rgba(120,90,50,.12)}
.est-sobrepostos{row-gap:calc(var(--slot) * .1)}
.est-sobrepostos .msdot{width:calc(100% - var(--slot) * .12)}
.est-fila .msdot{width:calc(100% - var(--slot) * .06)}
/* A TÁBUA EM ONDA das prateleiras que encaixam na de baixo (o que restou
   do formato ziguezague): os lugares assentam nos vales e a madeira sobe
   entre eles. Cada prateleira desenha a sua; empilhadas e desencontradas
   leem-se como o ziguezague de sempre — e agora cada fila é um nível seu,
   que é o que está no móvel.

   `--desvio` é o desencontro horizontal em frações de coluna e vem do JS
   (`layoutLocal`): com as duas prateleiras centradas, os lugares já caem
   uns entre os outros quando as capacidades têm paridades diferentes (4 e
   3), e só é preciso desviar quando são iguais. */
/* A prateleira ondulada não leva a barra reta por baixo: a madeira dela É
   o desenho da onda (`ondaBgSVG`), preenchida, com um vale sob cada lugar
   e um pico entre eles. */
/* A folga fica em BAIXO e não repartida: é para lá que o berço desce, e
   é o que deixa a garrafa assentar dentro dele em vez de flutuar por cima. */
.est-regua{padding:0 0 calc(var(--slot) * .29);
  background:none;border:none;box-shadow:none;border-radius:0;overflow:visible}
/* Nos sobrepostos a caixa tem duas filas: um pouco de folga em cima e as
   duas filas encostadas, que é como uma garrafa assenta na outra. A folga
   de baixo é menor do que na régua — a garrafa assenta EM CIMA da tábua
   lisa, não dentro de um berço, por isso só precisa da espessura dela. */
.est-regua.est-sobrepostos{padding:calc(var(--slot) * .08) 0 calc(var(--slot) * .29);row-gap:0}
.est-regua.est-lisa{padding-bottom:calc(var(--slot) * .1)}
/* A TÁBUA LISA do formato sobrepostos: a mesma madeira da régua (as duas
   cores dos traços dela, pela mesma ordem) e a mesma espessura, para o
   móvel se ler como um só. Vive colada ao fundo da caixa, como a régua. */
.est-bg-l{position:absolute;left:0;right:0;bottom:0;height:calc(var(--slot) * .17);
  border-radius:calc(var(--slot) * .03);pointer-events:none;
  background:linear-gradient(180deg,#f8ecd6,#efdcbb 55%,#e4cba2 84%,#d3b585 84%);
  border-top:1px solid #cdae7d;box-shadow:0 1px 2px rgba(90,60,25,.18)}
/* Capacidade ÍMPAR: as duas filas ficam desencontradas meia coluna, e aí a
   de cima assenta nos vãos da de baixo em vez de flutuar por cima dela — é
   como se empilham garrafas a sério, e é o mesmo passo (0,8) do
   encaixe entre níveis. A primeira fila da grelha fica com uma pista mais
   BAIXA do que o lugar: o lugar transborda-a metade para cada lado
   (`align-items:center`), e o que sobra em cima é exatamente o
   `padding-top`. Só com a régua — no seletor de posição (`.est-pick`) as
   filas ficam como estão, que ali a prateleira é para se tocar.
   Os 0,6/0,2 são o mesmo 0,8 de passo do encaixe entre níveis: a pista de
   cima mede `2 × 0,8 - 1`, e o que o lugar transborda dela para cima é o
   `1 - 0,8` do padding. */
.est-regua.est-sobrepostos.desenc{
  grid-template-rows:calc(var(--slot) * .6) auto;
  padding-top:calc(var(--slot) * .2)}
/* Dois traços sobre o mesmo caminho: o de baixo, mais grosso e escuro, é
   a sombra que dá espessura à régua; o de cima é a face clara. O
   `non-scaling-stroke` é obrigatório — o viewBox estica-se à caixa
   (`preserveAspectRatio:none`) e sem ele a régua saía mais grossa nas
   curvas do que nas retas. */
.est-reg-s,.est-reg{fill:none;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round}
.est-reg-s{stroke:#cbb894;stroke-width:calc(var(--slot) * .2)}
.est-reg{stroke:#fffdf7;stroke-width:calc(var(--slot) * .2)}
/* A TÁBUA CHEIA: o corpo em madeira clara, uma aresta escura no fundo a
   dar-lhe espessura, e um fio na borda de cima a desenhar o recorte do
   berço. `non-scaling-stroke` porque o viewBox estica-se à caixa. */
.est-tab{fill:url(#est-mad)}
.est-tab-esp{fill:#d3b585}
.est-tab-borda{fill:none;stroke:#cdae7d;stroke-width:1.3px;vector-effect:non-scaling-stroke;
  stroke-linecap:round;stroke-linejoin:round}
/* O ENCAIXE a sério: a prateleira que encaixa DESCE para dentro da de
   baixo, e é a sobreposição que o desenha. As duas filas já estavam
   desencontradas meia coluna — a garrafa de cima cai entre a primeira e a
   segunda de baixo, e a última fica logo a seguir à última — mas
   separadas por um intervalo isso lia-se como duas filas independentes,
   não como um encaixe.

   O valor é geometria e não gosto: com os lugares quase a tocarem-se, um
   círculo que caia meia coluna à frente assenta no V entre dois de baixo
   quando os centros ficam a ~0,8 do diâmetro; a linha mede 1,22 (o lugar
   mais a folga onde o berço desce) e a seguinte traz 0,14 de margem, logo
   -0,56 daqui (as margens de irmãos colapsam: -0,42 de passo). Chegou a
   ser calculado a partir do `--colr` para acompanhar o espaçamento entre
   garrafas — e o que isso fazia era mexer no espaço entre NÍVEIS, que já
   estava como se queria. São duas medidas independentes: esta é do
   encaixe, o `--colr` é do ar entre garrafas da MESMA prateleira.

   Chegou a não haver sobreposição nenhuma, por causa da FITA que a
   versão antiga desenhava por trás dos lugares — tapada, sobravam uns
   arcos soltos. Com a régua fina de agora é o contrário: os vales dela
   passam entre as garrafas de baixo, e é isso que se quer ver.

   A margem é de BAIXO e não de cima: os níveis desenham-se ao contrário
   (o mais alto primeiro, `prateleirasDesc`), por isso a prateleira que
   encaixa aparece ACIMA daquela em que assenta, e é o intervalo até à
   SEGUINTE que ela tem de fechar. Com `margin-top` fechava o de cima —
   e cada par encaixava no par errado. As margens de irmãos colapsam, e
   é isso que dá os -0,42 pedidos (0,14 do topo do próximo, -0,56 daqui). */
.mprat-layout.encaixa{margin-bottom:calc(var(--slot,34px) * -.56)}
/* A régua é uma TIRA colada ao fundo, com altura própria — e não
   `inset:0`. Esticada à caixa inteira, o mesmo viewBox dava uma régua mais
   alta nos `sobrepostos` (duas filas) do que na `fila`, e os berços fugiam
   de debaixo dos lugares. Com altura fixa em `--slot`, o berço cai sempre
   à mesma distância do fundo da garrafa, seja qual for o formato.
   O `<svg>` precisa de largura E altura declaradas: é um elemento de
   substituição, e a dimensão que falta sai da proporção do viewBox, não do
   posicionamento. */
.est-bg{position:absolute;left:0;right:0;bottom:0;width:100%;height:calc(var(--slot) * .68);
  pointer-events:none;overflow:visible}
.msdot{position:relative;z-index:1;aspect-ratio:1/1;width:100%;max-width:var(--slot);margin:0 auto;border-radius:999px;
  border:1px solid #c9a1af;background:#f3e8ec;display:flex;align-items:center;justify-content:center;
  font-family:var(--fd);font-size:clamp(8px,calc(var(--slot) * .42),15px);color:var(--vh);font-weight:600;
  line-height:1;font-variant-numeric:lining-nums}
/* Quase opaco e não translúcido: com as prateleiras encaixadas, a régua
   da de cima passa por trás dos lugares da de baixo — e num lugar
   translúcido via-se o traço a atravessar o círculo, como se a madeira
   lhe passasse por dentro. */
.msdot.vazia{border-style:dashed;border-color:#cdb1ba;background:rgba(255,255,255,.88);color:var(--mu);font-weight:400;
  font-family:var(--fd);padding:0;transition:background .15s,border-color .15s,transform .12s}
/* Um lugar vazio TAMBÉM se toca (para lá pôr um vinho) — mas só onde há
   o que tocar: numa garrafeira emprestada é só um buraco desenhado. */
body:not(.readonly) .msdot.vazia{cursor:pointer}
body:not(.readonly) .msdot.vazia:hover{background:#fff;border-color:var(--vh);color:var(--vh);transform:translateY(-1px)}
.msdot.cheia{background:var(--vh);border-color:var(--vh);color:#fff;cursor:pointer;font-family:inherit;font-weight:700;
  box-shadow:0 2px 4px rgba(78,18,40,.25),inset 0 1px 0 rgba(255,255,255,.18);transition:transform .12s,box-shadow .15s}
.msdot.cheia:hover{transform:translateY(-1px);box-shadow:0 4px 8px rgba(78,18,40,.3)}
.msdot.conflito{background:#8f2f4d;border-color:#8f2f4d}
/* Ocupado, mas por uma garrafa que NÃO passa na procura: apagado, para o
   que passa ficar a cor. */
.msdot.fora{background:#e6dee1;border-color:#e6dee1;color:#a8969c;box-shadow:none}
.msdot-id{display:block;max-width:100%;padding:0 2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.msdot-q{position:absolute;right:calc(var(--slot) * -.1);top:calc(var(--slot) * -.1);font-size:calc(var(--slot) * .3);
  font-weight:700;color:#fff;background:#c36c4f;border-radius:99px;padding:0 3px;line-height:1.4}
.mspot-pop{position:fixed;left:-9999px;top:-9999px;z-index:180;width:min(292px,calc(100vw - 16px));display:none}
.mspot-pop.on{display:block}
.mspot-card{background:var(--card);border:1px solid var(--bo2);border-radius:16px;padding:12px;box-shadow:0 20px 40px -18px rgba(30,8,16,.45)}
.mspot-head{font-size:10.5px;font-weight:700;letter-spacing:.8px;text-transform:uppercase;color:var(--mu);margin-bottom:10px}
.mspot-item+.mspot-item{margin-top:12px;padding-top:12px;border-top:1px solid var(--bo)}
.mspot-top{display:flex;align-items:center;gap:11px}
.mspot-thumb{position:relative;width:54px;height:84px;flex-shrink:0;border-radius:11px;background:linear-gradient(160deg,#fff,var(--bg2));
  border:1px solid var(--bo);display:flex;align-items:center;justify-content:center;overflow:hidden}
.mspot-thumb svg{width:100%;height:auto;max-height:74px;padding:5px 3px;filter:drop-shadow(0 2px 4px rgba(43,10,22,.18))}
.mspot-thumb img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.mspot-tx{min-width:0;flex:1}
.mspot-nome{font-family:var(--fd);font-weight:600;font-size:16px;line-height:1.25;color:var(--tx)}
.mspot-meta{font-size:11.5px;color:var(--mu);margin-top:4px;line-height:1.45}
.mspot-aux{font-size:11px;color:#8f4b2d;margin-top:6px}
.mspot-actions{display:grid;gap:7px;margin-top:12px}
.mspot-actions .mini{display:flex;align-items:center;justify-content:center;width:100%}

/* ── CONSUMIDOS ─────────────────────────────────────────────────── */
.ccard{background:var(--card);border:1px solid var(--bo);border-radius:var(--r);padding:13px 15px;margin-bottom:10px;
  position:relative;overflow:hidden;box-shadow:var(--sh)}
.ccard::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--ou)}
.cc-top{display:flex;justify-content:space-between;gap:10px;align-items:baseline}
.cc-nome{font-family:var(--fd);font-weight:600;font-size:15px}
.cc-data{font-size:11.5px;color:var(--mu);white-space:nowrap}
.cc-onde{font-size:12.5px;color:var(--tx);margin-top:5px}
.cc-nota{font-family:var(--fd);font-size:13px;color:var(--mu);font-style:italic;margin-top:5px;line-height:1.6}
.estrelas{color:var(--ou);font-size:12px;letter-spacing:2px;margin-top:4px}

/* ── DEFINIÇÕES ─────────────────────────────────────────────────── */
.fcard{background:var(--card);border:1px solid var(--bo);border-radius:var(--r);padding:16px 18px;margin-bottom:14px;box-shadow:var(--sh)}
.fcard h3{font-family:var(--fd);font-weight:600;font-size:16px;margin-bottom:8px}
.fcard h4{font-size:12.5px;font-weight:700;margin-bottom:6px}
.fcard label{display:block;font-size:10.5px;font-weight:600;letter-spacing:.7px;text-transform:uppercase;color:var(--mu);margin:10px 0 4px}
.fcard input,.fcard select,.fcard textarea{width:100%;padding:10px 12px;border:1px solid var(--bo);border-radius:9px;
  font-size:14px;font-family:inherit;background:var(--bg)}
.fcard input:focus,.fcard select:focus,.fcard textarea:focus{outline:none;border-color:var(--vh);background:#fff;box-shadow:0 0 0 3px var(--vhp)}
.btn{padding:10px 15px;border-radius:99px;border:1px solid var(--bo2);background:#fff;font-family:inherit;font-size:13px;
  font-weight:600;cursor:pointer;transition:all .15s;margin-top:10px}
.btn.prim{background:var(--vh);color:#fff;border-color:var(--vh);box-shadow:0 6px 16px -9px rgba(123,31,61,.9)}
.btn.prim:hover{background:var(--vh2)}
.btn.ghost:hover{background:var(--vhp);border-color:var(--vh);color:var(--vh)}
.btn.danger{background:#fff;color:var(--dg);border-color:#f0cbc9}
.btn.danger:hover{background:var(--dgp)}
.btn:disabled{opacity:.55;cursor:default}
.btn.full{width:100%}
.linha-add{display:flex;gap:7px;flex-wrap:wrap;align-items:flex-end;margin-top:10px}
.linha-add input,.linha-add select{flex:1;min-width:130px;padding:10px 12px;border:1px solid var(--bo);border-radius:9px;font-size:13.5px;font-family:inherit;background:var(--bg)}
.linha-add .btn{margin-top:0}
.ga-nav{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:8px;align-items:center}
.ga-nav-now{min-width:0;padding:9px 12px;border:1px solid var(--bo);border-radius:10px;background:#fff;text-align:center}
.ga-nav-now b{display:block;font-family:var(--fd);font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ga-nav-btn{width:36px;height:36px;border-radius:999px;border:1px solid var(--bo2);background:#fff;color:var(--vh);font-size:18px;line-height:1;cursor:pointer}
.ga-nav-btn:hover{border-color:var(--vh);background:var(--vhp)}
.ua-row{display:flex;align-items:center;flex-wrap:wrap;gap:6px 8px;padding:10px 0;border-bottom:1px solid var(--bo);font-size:13px}
.ua-row:last-child{border-bottom:none}
/* `flex-basis:100%` força o email a ocupar sempre a linha toda: com o
   plano de IA a somar-se ao checkbox de editor e ao ✕, os controlos já não
   cabiam ao lado do email num telemóvel — e um span `flex:1` (basis 0%)
   nunca força quebra de linha sozinho (o texto com ellipsis tem min-content
   ~0), por isso encolhia até desaparecer em vez de quebrar. */
.ua-row span.em{flex:1 1 100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}
.ua-row .tagme{font-family:var(--fd);font-size:12px;background:var(--vhp);color:var(--vh);padding:1px 9px;border-radius:99px;white-space:nowrap}
/* O editor das prateleiras (modal do local): uma linha por prateleira,
   com o nome editável no sítio (sem caixa — é um título) e por baixo o
   formato e os lugares. O formato é um botão com os pontinhos do desenho
   e abre a folha `.fmt-lista`. Prefixado com `.mbox` onde é preciso
   ganhar a `.mbox input`/`.mbox label`, que põem tudo em maiúsculas e
   com caixa. */
.ll-toggle{margin-top:14px}
.ll-toggle.chk{display:flex;align-items:center;gap:8px;margin:16px 0 0;font-size:13px;font-weight:600;letter-spacing:0;text-transform:none;color:var(--tx);cursor:pointer}
.ll-toggle.chk input{width:17px;height:17px;flex:0 0 auto;margin:0;padding:0;border:none;border-radius:0;background:none;accent-color:var(--vh);box-shadow:none}
#loc-layout-box>.note{margin-top:4px}
.ll-lista{display:grid;gap:10px;margin-top:12px}
.ll-row{padding:8px 12px 12px;border:1px solid var(--bo);border-radius:12px;background:var(--bg)}
.ll-head{display:flex;align-items:center;gap:8px}
.mbox input.ll-nome{flex:1;min-width:0;padding:5px 0;border:none;border-bottom:1px solid transparent;border-radius:0;background:none;
  font-family:var(--fd);font-weight:600;font-size:15px;color:var(--tx)}
.mbox input.ll-nome:focus{box-shadow:none;border-bottom-color:var(--vh);background:none}
.ll-del{margin:0;flex-shrink:0}
.ll-del:disabled{opacity:.25;cursor:default}
.ll-fields{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(76px,1fr);gap:10px}
.mbox .ll-fields label{margin:4px 0 4px}
.mbox .ll-fields input{background:#fff}
.ll-fmt{display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;min-height:47px;padding:8px 9px 8px 12px;
  border:1px solid var(--bo);border-radius:10px;background:#fff;cursor:pointer;font-family:inherit;color:var(--mu);transition:border-color .15s}
.ll-fmt:hover{border-color:var(--vh)}
.ll-caret{width:11px;height:18px;flex-shrink:0;opacity:.6}
.llprev{display:grid;grid-template-columns:repeat(var(--cols),auto);grid-template-rows:repeat(var(--rows),auto);
  gap:3px 4px;align-items:center;justify-items:center;width:auto}
.llprev-sobrepostos{gap:3px 0}
.llprev-sobrepostos .llprev-dot{margin:0 2px}
.llprev-dot{display:block;width:10px;height:10px;border-radius:50%;background:linear-gradient(180deg,#9a3656,#6d1837);box-shadow:inset 0 0 0 1px rgba(67,15,34,.18)}
.ll-odd{display:flex;align-items:center;gap:10px;margin-top:10px;font-size:12px;color:var(--mu)}
.mbox label.ll-enc{display:flex;align-items:center;gap:8px;margin:10px 0 0;padding:0;font-size:12px;
  letter-spacing:0;text-transform:none;color:var(--tx);cursor:pointer}
.mbox label.ll-enc input{width:16px;height:16px;flex:0 0 auto;margin:0;padding:0;border:none;border-radius:0;
  background:none;accent-color:var(--vh);box-shadow:none}
.ll-enc i{font-style:normal;color:var(--mu)}
.ll-odd .segbtn{padding:5px 11px;font-size:11.5px}
.ll-add{margin-top:12px}
/* A folha "Formato da prateleira": três opções ilustradas, a escolhida
   com o rebordo bordô e o ✓. Abre por cima do modal do local. */
.fmt-lista{display:grid;gap:10px;margin-top:14px}
.fmt-opt{display:flex;align-items:center;gap:14px;width:100%;padding:16px 14px;border:1px solid var(--bo);border-radius:14px;background:#fff;
  cursor:pointer;font-family:inherit;text-align:left;color:var(--tx);transition:all .15s;-webkit-tap-highlight-color:transparent}
.fmt-opt .llprev{flex:0 0 auto;width:84px;justify-content:center}
.fmt-opt .llprev-dot{width:14px;height:14px}
.fmt-tx{flex:1;min-width:0}
.fmt-tx b{display:block;font-family:var(--fd);font-weight:600;font-size:15px}
.fmt-tx i{display:block;font-style:normal;font-size:11.5px;color:var(--mu);margin-top:2px}
.fmt-ok{width:22px;text-align:center;color:var(--vh);font-weight:700;font-size:16px;opacity:0;transition:opacity .15s}
.fmt-opt:hover{border-color:var(--bo2);background:var(--bg)}
.fmt-opt.on{border-color:var(--vh);background:linear-gradient(180deg,#fff,var(--vhp));box-shadow:0 0 0 1px var(--vh)}
.fmt-opt.on .fmt-ok{opacity:1}
.lpick{margin:10px 0 2px;padding:12px;border:1px solid var(--bo);border-radius:12px;background:linear-gradient(180deg,#fffdf8,#f8f3ea)}
.lpick-top{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;margin-bottom:10px}
.lpick-n{font-family:var(--fd);font-size:13px;color:var(--vh);white-space:nowrap}
.lprat{overflow-x:auto}
.lprat+.lprat{margin-top:10px;padding-top:10px;border-top:1px solid var(--bo)}
.lprat-t{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:11px;font-weight:700;color:var(--mu);margin-bottom:7px}
.lprat-t span{font-family:var(--fd);font-size:12px;font-weight:400;color:var(--vh)}
/* No seletor os lugares têm largura fixa (cabe a garrafinha e o número)
   e a prateleira rola de lado se for comprida. */
.est-pick{--slot:46px;grid-template-columns:repeat(var(--gcols,var(--cols)),minmax(calc(var(--slot) / var(--span,1)),1fr));
  width:100%;min-width:calc(var(--cols) * var(--slot));max-width:none;margin:0;align-items:stretch;gap:7px;padding:8px 10px}
.est-pick.est-sobrepostos{row-gap:5px;column-gap:0}
/* No seletor a prateleira é para se TOCAR: os lugares ficam do mesmo
   tamanho em todos os formatos e a tábua em onda não desvia nada (o
   desencontro é desenho, e aqui o que interessa é acertar com o dedo). */
.est-pick.est-sobrepostos{--slot:44px}
.est-pick.est-regua{padding:6px 4px;transform:none}
.est-pick .lpslot{height:100%;min-height:52px}
.est-pick.est-sobrepostos .lpslot{margin:0 3px}
.lpslot{position:relative;z-index:1;border:1px solid var(--bo2);border-radius:10px;background:#fff;padding:7px 0 6px;font-family:inherit;color:var(--vh);cursor:pointer;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;min-height:50px}
.lpslot span{font-family:var(--fd);font-size:12.5px;line-height:1}
.lpslot svg{width:12px;height:auto;display:block;flex-shrink:0}
.lpslot.mini{min-height:40px;padding:6px 0 5px}
.lpslot.on{background:var(--vh);border-color:var(--vh);color:#fff}
.lpslot.ocup{background:#efe7da;border-color:#dfd1bb;color:var(--mu);cursor:default;opacity:.85}
.lpslot:disabled{pointer-events:none}
.lpick-foot{margin-top:8px}
/* `.ua-ctrls` é a segunda linha da linha (editor + plano de IA + tirar
   acesso): também com `flex-basis:100%` para cair sempre por baixo do
   email, nunca ao lado. Reafirma-se aqui `display/padding/border/…` do
   `.chk`/`.mini` porque `.fcard label`/`.fcard select` (para campos de
   formulário a sério) têm mais especificidade do que uma classe sozinha —
   sem isto ganhavam eles, e era isso que dava o checkbox enorme sozinho
   numa linha e o <select> a esticar para a largura toda do cartão. */
.ua-ctrls{display:flex;align-items:center;gap:10px;flex:1 1 100%}
.ua-row .chk{display:flex;align-items:center;gap:6px;margin:0;font-size:12.5px;font-weight:600;letter-spacing:0;text-transform:none;color:var(--tx);cursor:pointer;white-space:nowrap}
.ua-row .chk input{width:16px;height:16px;margin:0;padding:0;border:none;border-radius:0;background:none;accent-color:var(--vh);cursor:pointer}
.ua-row select.mini{width:auto;flex:0 1 auto;min-width:0;padding:5px 24px 5px 12px;font-size:11.5px;border:1px solid var(--bo2);border-radius:99px;background:#fff}
.ua-row .jdel{margin-left:auto}
.jdel{background:none;border:none;font-size:15px;cursor:pointer;color:var(--dg);padding:3px 6px;line-height:1}
.chk{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--mu);cursor:pointer;white-space:nowrap}
.chk input{width:auto;margin:0}
.diag-l{font-size:11px;font-family:ui-monospace,Menlo,monospace;padding:6px 0;border-bottom:1px solid var(--bo);line-height:1.5;word-break:break-word}


/* ── FAB ────────────────────────────────────────────────────────── */
.fab{position:fixed;right:18px;bottom:calc(20px + env(safe-area-inset-bottom,0px));width:56px;height:56px;border-radius:50%;
  border:none;background:linear-gradient(160deg,var(--vh2),var(--vhd));color:#fff;font-size:28px;line-height:1;cursor:pointer;
  box-shadow:0 8px 26px -6px rgba(78,18,40,.7);z-index:90;display:flex;align-items:center;justify-content:center;transition:transform .13s}
.fab:active{transform:scale(.93)}

/* ── MODAIS ───────────────────────────────────────────────────────
   No telemóvel são folhas que sobem de baixo (e é a folha que faz
   scroll, não a página por trás). O `input[type=date]` leva regra
   própria: no iOS ele não encolhe sozinho e saía pela borda fora — é
   preciso min-width:0 e tirar-lhe o aspeto nativo. */
.modal{display:none;position:fixed;inset:0;z-index:200;background:rgba(35,12,20,.55);backdrop-filter:blur(3px);
  overflow-y:auto;padding:20px 14px;align-items:flex-start;justify-content:center}
.modal.on{display:flex;animation:fadein .16s ease both}
@keyframes fadein{from{opacity:0}to{opacity:1}}
.mbox{background:var(--card);border-radius:var(--r2);width:100%;max-width:540px;padding:20px;box-shadow:0 24px 60px -12px rgba(30,8,16,.55);
  margin:auto;animation:subir .22s cubic-bezier(.2,.8,.3,1) both}
@keyframes subir{from{opacity:0;transform:translateY(14px) scale(.99)}to{opacity:1;transform:none}}
.mtop{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:4px}
.mtop h3{font-family:var(--fd);font-weight:600;font-size:19px;line-height:1.25}
.mx{background:var(--bg2);border:none;width:30px;height:30px;border-radius:50%;font-size:15px;line-height:1;color:var(--mu);
  cursor:pointer;flex-shrink:0;display:flex;align-items:center;justify-content:center;transition:all .15s}
.mx:hover{background:var(--vh);color:#fff}
.mbox label{display:block;font-size:10.5px;font-weight:600;letter-spacing:.7px;text-transform:uppercase;color:var(--mu);margin:13px 0 5px}
.mbox input,.mbox select,.mbox textarea{width:100%;min-width:0;max-width:100%;padding:11px 13px;border:1px solid var(--bo);
  border-radius:10px;font-size:15px;font-family:inherit;background:var(--bg)}
.mbox input:focus,.mbox select:focus,.mbox textarea:focus{outline:none;border-color:var(--vh);background:#fff;box-shadow:0 0 0 3px var(--vhp)}
.mbox textarea{resize:vertical;min-height:70px;line-height:1.55}
input[type=date]{-webkit-appearance:none;appearance:none;display:block;min-width:0;max-width:100%;
  background-clip:padding-box;text-align:left}
input[type=date]::-webkit-date-and-time-value{text-align:left;margin:0;min-width:0}
input[type=date]::-webkit-calendar-picker-indicator{opacity:.55;margin-left:auto}
/* Num local com desenho a prateleira não se escreve: sai do número do
   lugar (ver `renderPickerPosicoes`). Fica à vista, apagada, porque é
   informação — o que se edita é o lugar. */
#g-pratbox.derivado input{background:var(--bg2);color:var(--mu);border-style:dashed}
.mrow{display:flex;gap:10px}
.mrow>div{flex:1;min-width:0}
.macoes{display:flex;gap:8px;flex-wrap:wrap;margin-top:18px}
.macoes .btn{margin-top:0;flex:1 1 auto;min-width:0}
.mdet{margin-top:12px}
.mdl{display:flex;gap:12px;padding:9px 0;border-bottom:1px solid var(--bo);font-size:13.5px;line-height:1.55}
.mdl:last-child{border-bottom:none}
.mdl b{flex:0 0 104px;font-size:10px;font-weight:600;letter-spacing:.7px;text-transform:uppercase;color:var(--mu);padding-top:3px}
.mdl span{flex:1;min-width:0}
.msec{display:flex;align-items:center;gap:9px;font-size:10.5px;font-weight:600;letter-spacing:.9px;text-transform:uppercase;
  color:var(--vh);margin:20px 0 4px}
.msec::after{content:'';flex:1;height:1px;background:linear-gradient(90deg,var(--vh),transparent);opacity:.35}
.mgar{background:var(--bg);border:1px solid var(--bo);border-radius:11px;padding:10px 12px;margin-top:8px;
  display:flex;align-items:center;gap:9px;font-size:12.5px;flex-wrap:wrap}
.mgar .g-onde{flex:1;min-width:150px}
.mgar .g-onde b{display:block;font-size:13px;font-weight:600;color:var(--tx);text-transform:none;letter-spacing:0}
.mgar .g-onde i{font-size:11px;color:var(--mu);font-style:normal;display:block;margin-top:2px}
/* A posição na prateleira é a SEGUNDA linha: o sítio primeiro, depois o
   nível e o lugar. Numa linha só, o nome do local partia-se a meio. */
.mgar .g-onde .g-pos{display:block;font-size:12px;color:var(--tx);margin-top:1px}
/* Links do vinho: pequenos, seguidos por vírgula, numa linha só (em vez
   de uma caixa `.mgar` por link) — o ✕ de remover cola-se ao nome, não
   fica num botão à parte. */
.mlinks{margin-top:8px;font-size:12.5px;line-height:1.7}
.mlinks a{color:var(--in)}
.mlink-x{border:none;background:none;padding:0 0 0 3px;font-size:10px;color:var(--mu);cursor:pointer;font-family:inherit;vertical-align:middle}
.mlink-x:hover{color:var(--vh)}
.mini{padding:6px 11px;font-size:11.5px;border-radius:99px;border:1px solid var(--bo2);background:#fff;font-family:inherit;
  cursor:pointer;white-space:nowrap;font-weight:600;transition:all .15s}
.mini:hover{border-color:var(--vh);color:var(--vh)}
.mini.p{background:var(--vh);color:#fff;border-color:var(--vh)}
.mini.o{background:var(--oup);color:var(--ou2);border-color:#eddfba}

/* Cabeçalho do modal do vinho: a garrafa, o nome e a origem sobre o
   bordô. É o que dá a "capa" à ficha — o resto do modal fica papel.

   A imagem é a MESMA moldura da miniatura da lista, só maior: fundo de
   papel, cantos redondos, `overflow:hidden` e `object-fit:cover`. Antes
   não tinha altura definida nem overflow e usava `contain`: a foto ficava
   um quadrado branco no meio do bordô, com a garrafa desenhada a espreitar
   por cima e por baixo. Se lhe mexeres, mexe também na `.vc-thumb` — são a
   mesma ideia em dois tamanhos. */
.mhero{position:relative;margin:-20px -20px 4px;padding:18px 18px 16px;border-radius:var(--r2) var(--r2) 0 0;
  background:linear-gradient(155deg,#3d0e20,var(--vhd) 55%,#8d2748);color:#fff;overflow:hidden}
.mhero::after{content:'';position:absolute;left:0;right:0;bottom:0;height:2px;
  background:linear-gradient(90deg,transparent,var(--ou),transparent);opacity:.8}
.mhero .mx{position:absolute;top:12px;right:12px;background:rgba(255,255,255,.14);color:#fff}
.mhero .mx:hover{background:rgba(255,255,255,.3)}
.mhero-in{display:flex;gap:14px;align-items:center;padding-right:34px}
.mhero-g{width:64px;height:104px;flex-shrink:0;position:relative;display:flex;align-items:center;
  justify-content:center;overflow:hidden;border-radius:11px;padding:0;cursor:pointer;
  -webkit-tap-highlight-color:transparent;
  background:linear-gradient(160deg,#fff,var(--bg2));border:1px solid rgba(255,255,255,.5);
  box-shadow:0 8px 20px -8px rgba(0,0,0,.6)}
.mhero-g svg{width:100%;height:auto;max-height:94px;padding:5px 3px;filter:drop-shadow(0 2px 4px rgba(43,10,22,.22))}
.mhero-g img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.mhero-tx{min-width:0;flex:1}
.mhero-k{font-size:10px;font-weight:600;letter-spacing:1.1px;text-transform:uppercase;color:rgba(255,255,255,.7)}
.mhero h3{font-family:var(--fd);font-weight:600;font-size:21px;line-height:1.2;margin-top:4px}
.mhero-s{font-size:12px;color:rgba(255,255,255,.78);margin-top:4px}
.mhero-n{display:inline-flex;align-items:center;gap:5px;margin-top:8px;background:rgba(255,255,255,.12);
  border:1px solid rgba(255,255,255,.22);border-radius:99px;padding:3px 10px;font-size:11px;font-weight:600;color:#f6dfa8}

/* A imagem em grande (toca-se na capa do modal do vinho). O palco tem
   altura fixa e a imagem entra em `contain`: umas fotos são da garrafa
   inteira, outras só do rótulo — cortar era deformar. */
.mhero-lupa{position:absolute;right:4px;top:4px;width:19px;height:19px;border-radius:7px;
  background:rgba(28,10,16,.6);color:#fff;font-size:9.5px;display:flex;align-items:center;
  justify-content:center;backdrop-filter:blur(2px);pointer-events:none}
/* A garrafa desenhada fica SEMPRE por baixo e a fotografia por cima. Assim
   não há palco vazio enquanto a imagem carrega (nem se o link estiver
   morto — aí o `onerror` tira-a e fica a garrafa). É o mesmo que o cartão
   faz na miniatura. */
.foto-palco{position:relative;margin-top:14px;background:var(--bg);border:1px solid var(--bo);border-radius:12px;
  height:min(52vh,420px);display:flex;align-items:center;justify-content:center;overflow:hidden;padding:10px}
.foto-palco img{position:absolute;inset:10px;width:calc(100% - 20px);height:calc(100% - 20px);
  object-fit:contain;display:block;border-radius:6px;background:var(--bg)}
.foto-svg{height:100%;display:flex;align-items:center;justify-content:center}
.foto-svg svg{height:100%;width:auto;max-height:100%;filter:drop-shadow(0 6px 14px rgba(43,10,22,.25))}
#foto-estado:empty{display:none}
#foto-estado{margin-top:10px}
/* O botão de carregar é um <label> (é ele que abre o seletor de ficheiros),
   e `.mbox label` põe tudo em maiúsculas a 10px — daí a especificidade. */
.mbox label.btn{text-transform:none;letter-spacing:0;font-size:13px;font-weight:600;margin:0;
  display:flex;align-items:center;justify-content:center;gap:7px}

/* Estrelas de avaliação (consumo) — em vez do <select>, que ninguém
   percebia ser uma nota. */
.stars{display:flex;gap:5px;margin-top:5px}
.star{width:38px;height:34px;border:1px solid var(--bo);background:var(--bg);border-radius:9px;font-size:15px;
  cursor:pointer;color:#cdc2ba;font-family:inherit;transition:all .12s;display:flex;align-items:center;justify-content:center}
.star.on{color:var(--ou);background:var(--oup);border-color:#eddfba}
.star:hover{transform:translateY(-1px)}
.stars-l{font-size:11px;color:var(--mu);margin-top:6px}

/* Seletor do que procurar (antes da procura).
   Prefixado com `.mbox` de propósito: `.mbox label` põe TUDO em maiúsculas,
   a 10px e display:block — e como é mais específico do que uma classe
   sozinha, sem isto o seletor saía com os nomes dos campos em maiúsculas e
   os visto desalinhados. */
.ia-escbar{display:flex;align-items:center;gap:7px;margin-top:14px;flex-wrap:wrap}
.ia-escbar .note{flex:1;text-align:right;min-width:80px}
.ia-escs{display:grid;grid-template-columns:repeat(auto-fill,minmax(148px,1fr));gap:0 14px;margin-top:10px}
.mbox .ia-esc{display:flex;align-items:flex-start;gap:9px;margin:0;padding:8px 2px;cursor:pointer;
  font-size:12.5px;font-weight:500;text-transform:none;letter-spacing:0;color:var(--tx);line-height:1.3;
  border-bottom:1px solid var(--bo);-webkit-tap-highlight-color:transparent}
.mbox .ia-esc input{width:auto;margin:1px 0 0;flex-shrink:0;accent-color:var(--vh)}
.mbox .ia-esc span{min-width:0}
.mbox .ia-esc i{display:block;font-style:normal;font-size:10px;color:var(--mu);margin-top:1px}
.ia-linha{display:flex;gap:10px;align-items:flex-start;padding:10px 0;border-bottom:1px solid var(--bo)}
.ia-linha:last-child{border-bottom:none}
.ia-linha input[type=checkbox]{width:auto;margin-top:3px;flex-shrink:0}
.ia-campo{flex:1;min-width:0;font-size:13px;line-height:1.55}
.ia-campo b{display:block;font-size:10px;font-weight:600;letter-spacing:.7px;text-transform:uppercase;color:var(--mu)}
.ia-antes{color:var(--mu);text-decoration:line-through;font-size:12px}
/* A comparação entre motores. O premium é DOURADO porque nesta app o dourado
   é a cor da distinção (menção, nota do Vivino) — e o que se distingue aqui é
   a leitura que custou dinheiro. A grátis fica em papel, como o resto. */
.ia-cmp{padding:10px 0;border-bottom:1px solid var(--bo)}
.ia-cmp:last-child{border-bottom:none}
.ia-cmp-t{display:block;font-size:10px;font-weight:600;letter-spacing:.7px;text-transform:uppercase;color:var(--mu);margin-bottom:6px}
.ia-op{display:flex;gap:9px;align-items:flex-start;margin-top:5px;padding:6px 9px;border:1px solid var(--bo);border-radius:9px;background:var(--card);font-size:13px;line-height:1.5;cursor:pointer}
.ia-op input{width:auto;margin-top:3px;flex-shrink:0}
.ia-op span{flex:1;min-width:0;word-break:break-word}
.ia-op i{display:block;font-style:normal;font-size:10px;font-weight:600;letter-spacing:.6px;text-transform:uppercase;color:var(--mu)}
.ia-op.at{background:transparent;color:var(--mu)}
.ia-op.pr{border-color:#eddfba;background:var(--oup)}
.ia-op.pr i{color:var(--ou2)}
.ia-op:has(input:checked){border-color:var(--vh);box-shadow:0 0 0 1px var(--vh)}
.ia-op.pr:has(input:checked){border-color:var(--ou);box-shadow:0 0 0 1px var(--ou)}
.ia-igual{font-style:normal;color:var(--vd)}
.ia-prbar{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-top:12px;padding:9px 11px;border:1px solid #f0e4c8;border-radius:11px;background:var(--oup);font-size:12.5px;color:var(--ou2)}
.ia-prbar span{flex:1;min-width:130px}
/* A faixa que diz que a ficha (ou parte dela) veio do CATÁLOGO PARTILHADO
   e não de uma pesquisa paga agora. Verde e não dourado de propósito: o
   dourado é a distinção (a menção, a nota do Vivino) e isto não distingue
   vinho nenhum — é a app a dizer que já sabia, que é uma boa notícia
   sobre a PROCURA e não sobre o vinho. */
.ia-cat{margin-top:12px;padding:9px 11px;border:1px solid #cfe3d8;border-radius:11px;background:var(--vdp);font-size:12.5px;color:var(--vd)}
.ia-fontes{font-size:11px;color:var(--mu);margin-top:12px;line-height:1.75;word-break:break-word}
.ia-fontes a{color:var(--in)}
.aviso{background:var(--oup);border:1px solid #eddfba;border-radius:11px;padding:11px 13px;font-size:12px;color:#6f5205;line-height:1.6;margin-top:12px}
.erro{background:var(--dgp);border:1px solid #f2cdcb;border-radius:11px;padding:11px 13px;font-size:12.5px;color:var(--dg);line-height:1.6;margin-top:12px}

@media(max-width:560px){
  .modal{padding:0;align-items:flex-end}
  .mbox{max-width:none;margin:0;border-radius:var(--r2) var(--r2) 0 0;max-height:94vh;overflow-y:auto;
    padding-bottom:calc(20px + env(safe-area-inset-bottom,0px));animation:folha .26s cubic-bezier(.2,.8,.3,1) both}
  @keyframes folha{from{transform:translateY(40px);opacity:.6}to{transform:none;opacity:1}}
  .mhero{border-radius:var(--r2) var(--r2) 0 0}
  .vc-thumb{width:46px}
  .vc-nome{font-size:15px}
}

/* ── PÁGINA DO VINHO ───────────────────────────────────────────────
   O detalhe de um vinho deixou de ser uma folha por cima da lista e
   passou a ser uma PÁGINA: ecrã inteiro, papel do princípio ao fim, e o
   cabeçalho do vinho COLADO ao topo — quem rola até "já bebidas"
   continua a ver de que vinho está a falar.

   Colado, mas não do tamanho todo: encolhe para uma barra ao rolar —
   garrafa pequena, nome numa linha. Fixo em tamanho grande comia meio
   telemóvel.

   Continua a ser o MESMO `#modal-vinho`, só com outra pele. É de
   propósito: os `fecharModal('modal-vinho')` espalhados pelo app.js, os
   modais que abrem POR CIMA (editar, consumir, foto, IA) e o
   `refrescarVinhoAberto()` continuam a funcionar sem saber de nada
   disto. Se um dia isto for uma `.sec` a sério, é aí que se paga.

   Nota de ordem: esta secção vem DEPOIS do `@media(max-width:560px)`
   dos modais e ganha-lhe por especificidade (`.modal.pagina .mbox`) —
   no telemóvel a folha sobe de baixo e é a `.mbox` que rola; aqui não,
   quem rola é a página inteira (é isso que faz o `sticky` pegar). */
.modal.pagina.on{display:block}   /* bloco e não flex: um item de flex não CRESCE
     com o que tem dentro — a folha parava à altura do ecrã e a ficha
     continuava por cima do papel, sem cartão por baixo */
.modal.pagina{padding:0;background:var(--bg);backdrop-filter:none;
  background-image:radial-gradient(circle at 1px 1px,rgba(78,18,40,.045) 1px,transparent 0);background-size:22px 22px;
  overscroll-behavior:contain;
  /* o gesto de sair é nosso (ver `pgSwipe`); o vertical fica do browser */
  touch-action:pan-y}
.modal.pagina .mbox{max-width:620px;max-height:none;overflow:visible;margin:0 auto;min-height:100%;
  border-radius:0;padding-top:0;padding-bottom:calc(26px + env(safe-area-inset-bottom,0px));
  box-shadow:0 0 50px -14px rgba(30,8,16,.22);
  /* SEM `both`: uma animação de `transform` que fica agarrada ao fim faz
     desta folha o ponto de referência do cabeçalho `fixed` lá dentro — e
     ele passava a rolar com ela em vez de ficar preso ao topo. */
  animation:pgentrar .22s cubic-bezier(.2,.8,.3,1)}
@keyframes pgentrar{from{opacity:0;transform:translateX(24px)}to{opacity:1;transform:none}}

/* `--pg` é o quanto o cabeçalho já encolheu: 0 por inteiro, 1 na barra.
   Quem lhe mexe é o `pgCabecalho()` a cada scroll — daí para baixo é
   tudo `calc()`, e é isso que faz a passagem acompanhar o dedo em vez de
   dar um salto a meio caminho. O valor por defeito TEM de estar aqui:
   sem ele, `var(--pg)` não resolve e cada `calc()` cai por inválido.

   `fixed` e não `sticky`, que é o que torna isto fluido: preso ao fluxo,
   cada pixel que o cabeçalho encolhia obrigava a recalcular a folha toda
   por baixo — 5ms por passo numa máquina de secretária, o triplo num
   telemóvel, e via-se aos bocados. Fora do fluxo, o encolher fica contido
   nele (`contain`) e a folha por baixo nem dá por isso; em troca, a
   `.mbox` leva um `padding-top` do tamanho do cabeçalho aberto (posto
   pelo `pgMedirEncolhe`) para a ficha começar por baixo dele. */
.modal.pagina .mhero{--pg:0;position:fixed;top:0;left:50%;transform:translateX(-50%);
  width:100%;max-width:620px;z-index:5;margin:0;border-radius:0;contain:layout paint;
  /* a altura vem do `pgCabecalho()`; o conteúdo fica centrado no que
     sobrar, que é o que esconde as quebras de linha lá dentro */
  display:flex;flex-direction:column;justify-content:center;
  padding:calc(18px - 10px*var(--pg)) 18px calc(16px - 8px*var(--pg));
  box-shadow:0 8px 22px -14px rgba(30,8,16,calc(.75*var(--pg)))}
/* Recuo só à DIREITA, para o ✕. À esquerda não há botão nenhum: um ‹
   custava outros 40px a toda a coluna do nome para repetir o que o ✕, o
   Escape, o voltar do telemóvel e o arrastar já fazem.
   O `gap` é FIXO de propósito (e a garrafa mantém a largura, ver abaixo):
   tudo o que muda a largura da coluna do nome obriga o browser a remontar
   o texto a cada passo do scroll. Só a ALTURA da garrafa é que encolhe. */
.modal.pagina .mhero-in{padding:0 40px 0 0;gap:14px}
/* `font-size:0` no bloco de texto e não nos filhos: os espaços em branco
   ENTRE as pastilhas contam como texto e, com elas encolhidas a zero,
   deixavam na barra uma linha fantasma de 21px (a altura da letra
   herdada) que nada preenchia. Cada filho aqui dentro põe o seu tamanho
   — se acrescentares texto solto a `.mhero-tx`, dá-lhe um. */
.modal.pagina .mhero-tx{font-size:0}
/* A moldura da garrafa encolhe de caixa (é ela que manda na altura da
   linha, e é ela que o `pgMedirEncolhe` mede); o desenho e a fotografia
   lá dentro só são ESCALADOS. Redimensioná-los obrigava o browser a
   remontar o SVG e a redesenhar a fotografia a cada passo do scroll —
   era o que sobrava do andar aos bocados depois de tirar o `font-size`.
   O 0.48 e os 64x104 andam juntos: mudar um pede mudar o outro. */
.modal.pagina .mhero-g{width:64px;height:calc(104px*(1 - .48*var(--pg)))}
.modal.pagina .mhero-g svg{width:64px;height:104px;max-height:none;padding:5px 3px;
  transform:scale(calc(1 - .48*var(--pg)))}
.modal.pagina .mhero-g img{inset:auto;width:64px;height:104px;transform:scale(calc(1 - .48*var(--pg)))}
/* O nome NÃO muda de tamanho — vai só perdendo LINHAS, inteiras e com
   reticências (`-webkit-line-clamp`, posto pelo `pgCabecalho()`), e cada
   uma sai quando a moldura já lá ia. Encolher a letra parecia boa ideia
   e era o pior salto que restava: a certa altura o nome mudava de quebra
   ("…Vale Meão / Douro Tinto…" passava a "…Vale Meão Douro / Tinto…") e
   as palavras saltavam de linha todas ao mesmo tempo. Com um `max-height`
   contínuo em vez do clamp era pior ainda: via-se o "Reserva" cortado a
   meio da altura das letras. */
.modal.pagina .mhero h3{margin-top:calc(4px*(1 - var(--pg)));
  display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden}
.modal.pagina .mhero-s{margin-top:calc(4px - 3px*var(--pg))}
/* O que desaparece pelo caminho não usa `display:none` (isso é o salto):
   a caixa fecha-se por RECORTE (`max-height`, `max-width`) e a opacidade
   apaga o que lá está — margens, padding e borda vão atrás, senão ficava
   o esqueleto do crachá. A opacidade vai ao triplo da velocidade para já
   não se ler nada enquanto a caixa ainda fecha.

   Recorte e NÃO `font-size`, que foi a primeira tentativa: mudar o
   tamanho da letra obriga o browser a remontar o texto letra a letra a
   cada passo do scroll — 3ms por passo só nestes três, mais do que tudo
   o resto junto, e era daí que vinha o andar aos bocados.

   E fecham ao DOBRO da velocidade do resto (`--pg2`): os extras saem
   primeiro, o nome fica até ao fim. Não é só gosto — a moldura encolhe a
   direito e, sem isto, o conteúdo ficava para trás no início e sobrava
   uns pixéis para fora dela. */
.modal.pagina .mhero{--pg2:clamp(0,calc(2*var(--pg)),1)}
.modal.pagina .mhero-k{max-height:calc(15px*(1 - var(--pg2)));overflow:hidden;
  opacity:clamp(0,calc(1 - 3*var(--pg)),1)}
.modal.pagina .mhero-n{max-height:calc(24px*(1 - var(--pg2)));overflow:hidden;
  opacity:clamp(0,calc(1 - 3*var(--pg)),1);margin-top:calc(8px*(1 - var(--pg2)));
  padding-top:calc(3px*(1 - var(--pg2)));padding-bottom:calc(3px*(1 - var(--pg2)));
  border-width:calc(1px*(1 - var(--pg2)))}
/* Encolhido fica o nome e o ANO: a origem inteira ("Olazabal & Filhos ·
   Douro · Cima Corgo · 2015") não cabe numa barra, e cortá-la levava a
   região atrás. Fecha-se por altura, como o resto — a largura nunca muda,
   que é o que impede o browser de voltar a quebrar o texto a cada passo.
   `--pg-hs` é a altura que ela ocupa mesmo (uma linha ou duas), medida
   pelo `pgMedirEncolhe`; um valor fixo aqui dava uma pausa a meio para
   quem tivesse origem de uma linha só.

   O ano vai atrás dela, por isso a barra tem a SUA cópia (`.mhero-ab`),
   que abre no fim. É uma palavra repetida no HTML e evita o único salto
   que faltava — sem a garrafa à vista, o ano é o que falta saber. */
.modal.pagina .mhero-s{max-height:calc(var(--pg-hs,44)*1px*(1 - var(--pg2)));overflow:hidden;
  opacity:clamp(0,calc(1 - 2.5*var(--pg)),1)}
.modal.pagina .mhero-ab{max-height:calc(18px*var(--pg));overflow:hidden;
  opacity:clamp(0,calc(2*var(--pg) - 1),1);font-size:12px;font-weight:600;color:rgba(255,255,255,.9)}
.mhero-ab{display:none}
.modal.pagina .mhero-ab{display:block}
/* O ✕ desce com o cabeçalho: os 12→20px são o que o deixa centrado na
   barra já encolhida. */
.modal.pagina .mhero .mx{top:calc(12px + 8px*var(--pg))}

/* Arrastar de lado para sair: a folha segue o dedo (sem transição, senão
   ia sempre atrás dele) e, se não chegar ao ponto de sair, volta ao
   lugar com uma. */
.modal.pagina.a-arrastar .mbox{animation:none;transition:none}
.modal.pagina.a-soltar .mbox{animation:none;transition:transform .2s ease,opacity .2s ease}

/* ── TOAST ──────────────────────────────────────────────────────── */
.toast{position:fixed;left:50%;bottom:26px;transform:translate(-50%,80px);background:var(--tx);color:#fff;
  padding:12px 20px;border-radius:99px;font-size:13px;z-index:400;opacity:0;transition:all .28s;pointer-events:none;
  max-width:88vw;text-align:center;line-height:1.4;box-shadow:0 10px 30px -8px rgba(0,0,0,.6)}
.toast.on{transform:translate(-50%,0);opacity:1}
.toast.err{background:var(--dg)}

/* ── PERMISSÕES ─────────────────────────────────────────────────────
   Quatro classes, quatro fronteiras diferentes:
     .ro-hide    esconde-se de quem NÃO pode editar (body.readonly)
     .admin-hide esconde-se de quem NÃO é admin     (body.naoadmin)
     .dono-hide  esconde-se de quem NÃO é o dono da conta Supabase
                 (body.naodono) — password temporária e diagnóstico mexem
                 na CONTA, não na garrafeira, e continuam a ser meus mesmo
                 depois de passar a app a outro admin.
     .minha-only mostra-se SÓ ao dono da garrafeira aberta (body.naominha
                 esconde-a) — partilhar, mudar o nome e passar a garrafeira
                 são coisas de quem é dono dela.
   `.minha-only` não é o mesmo que `.ro-hide`, e é por isso que existe: o
   cartão das Garrafeiras TEM de continuar visível numa garrafeira
   emprestada (é lá que está o caminho de volta à própria), e só o que lá
   dentro é do dono é que desaparece.
   Isto é só a UI. Quem manda é a RLS (pode_ver()/pode_mexer() em
   db/policies.sql) — esconder um botão nunca foi proteção nenhuma. */
body.readonly .ro-hide{display:none!important}
body.naoadmin .admin-hide{display:none!important}
body.naodono .dono-hide{display:none!important}
body.naominha .minha-only{display:none!important}

/* ── PRÉ-VISUALIZAÇÃO DA FOLHA (PDF) ────────────────────────────────
   Aqui só vive a MOLDURA — a barra e o iframe. O CSS da própria folha vive
   no `app.js` (`PDF_CSS`), dentro do documento que o iframe recebe, e é isso
   que a põe fora do alcance de qualquer regra desta folha de estilos.

   Havia aqui um `@media print` que escondia a app toda (`body>*{display:none}`)
   para deixar passar um `#print-area` montado na página viva. Era esse o
   arranjo que mandava folhas em branco para o papel: a folha ficava refém
   desta cascata e o `afterprint` limpava-a por baixo do trabalho de
   impressão. Não voltes a imprimir a página da app — imprime-se o documento
   isolado, e o `exportarPDF()` explica porquê.

   O z-index fica acima dos modais (200) e abaixo do toast (400): a folha
   abre-se por cima de tudo, mas um aviso ainda se lê. */
#pdf-pre{position:fixed;inset:0;z-index:250;background:var(--vhd);
  display:flex;flex-direction:column}
.pdfp-bar{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:10px 12px;background:var(--vh);color:#fff}
.pdfp-t{font-family:var(--fd);font-weight:600;font-size:15px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pdfp-acc{display:flex;gap:7px;flex:0 0 auto}
.pdfp-btn{padding:9px 13px;border-radius:99px;border:1px solid rgba(255,255,255,.35);
  background:rgba(255,255,255,.14);color:#fff;font-family:inherit;font-size:13px;font-weight:600;
  cursor:pointer;transition:all .15s;white-space:nowrap}
.pdfp-btn:hover{background:rgba(255,255,255,.26)}
.pdfp-btn.prim{background:#fff;color:var(--vh);border-color:#fff}
.pdfp-btn.prim:hover{background:var(--vhp)}
#pdf-pre-frame{flex:1 1 auto;width:100%;border:0;background:#fff}
/* No telemóvel a barra parte-se em duas linhas antes de deixar o botão de
   imprimir encolher — é o único que se toca a sério. */
@media(max-width:480px){
  .pdfp-bar{flex-wrap:wrap}
  .pdfp-t{flex:1 1 100%}
  .pdfp-acc{flex:1 1 100%;justify-content:flex-end}
}

/* ── O ESPELHO DO CATÁLOGO (ver "O ESPELHO DO CATÁLOGO" no app.js) ── */

/* A marquinha ao lado de um valor da ficha. Discreta — é um aviso, não um
   erro, e na esmagadora maioria dos vinhos nem aparece. */
.cat-marca{display:inline-flex;align-items:center;margin-left:6px;padding:1px 7px;
  font-size:10px;font-weight:700;border-radius:99px;border:1px solid #f2cdcb;
  background:var(--dgp);color:var(--dg);cursor:pointer;font-family:inherit;
  vertical-align:middle;line-height:1.6}
.cat-marca:hover{background:#f9d8d6}

/* A tira de resumo, por baixo dos botões de ação. Fica fora do `ro-hide`
   de propósito — ver o desacordo com o catálogo não é uma ação de escrita,
   é informação sobre o vinho, e quem só pode ver também tem direito a ela. */
.cat-tira{display:flex;align-items:center;gap:9px;margin-top:8px;padding:9px 12px;
  background:var(--bg);border:1px solid var(--bo);border-radius:11px;font-size:12px;
  color:var(--mu);cursor:pointer}
.cat-tira:hover{border-color:var(--bo2)}
.cat-tira.dif{background:var(--dgp);border-color:#f2cdcb;color:var(--dg)}
.cat-tira-i{flex-shrink:0;width:20px;height:20px;border-radius:50%;display:flex;
  align-items:center;justify-content:center;font-weight:700;font-size:12px;
  background:rgba(0,0,0,.06)}
.cat-tira.dif .cat-tira-i{background:rgba(179,38,30,.14)}
.cat-tira span:nth-child(2){flex:1;min-width:0}
.cat-tira span:nth-child(2) strong{color:var(--tx)}
.cat-tira.dif span:nth-child(2) strong{color:var(--dg)}
.cat-tira-v{flex-shrink:0;font-weight:600;text-decoration:underline}

/* O painel — cada campo com os dois valores lado a lado. */
#modal-catalogo-in .msec{margin-top:18px}
.cat-cmp{padding:11px 0;border-bottom:1px solid var(--bo)}
.cat-cmp:last-child{border-bottom:none}
.cat-cmp.focado{background:var(--vhp);margin:0 -14px;padding:11px 14px;border-radius:10px;border-bottom-color:transparent}
.cat-cmp-k{font-size:10.5px;font-weight:700;color:var(--mu);text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px}
.cat-cmp-v{display:flex;gap:8px;flex-wrap:wrap}
.cat-cmp-v .lado{flex:1 1 150px;min-width:0;background:var(--card);border:1px solid var(--bo);
  border-radius:10px;padding:8px 10px}
.cat-cmp-v .lado.deles{background:var(--oup);border-color:#eddfba}
.cat-cmp-v .lado span{display:block;font-size:9.5px;font-weight:700;color:var(--mu);
  text-transform:uppercase;letter-spacing:.4px}
.cat-cmp-v .lado b{display:block;font-size:13.5px;margin-top:2px;word-break:break-word;color:var(--tx)}
.cat-de{display:block;margin-top:5px;font-style:normal;font-size:10.5px;color:var(--ou2)}
.cat-de.f3{color:var(--ou2)}
.cat-de.f2{color:var(--vh)}
.cat-de.f1,.cat-de.f0{color:var(--mu)}
.cat-cmp-a{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}

@media (max-width:520px){
  .cat-cmp-v{flex-direction:column}
}

/* ═══════════════════════════════════════════════════════════════════════
   POLIMENTO VISUAL — MAPA DOS LOCAIS / FORMATOS
   Apenas pele visual: não altera dados, eventos, lógica ou comportamento.
   ═══════════════════════════════════════════════════════════════════════ */

/* Editor: formato e quantidade ficam lado a lado, compactos. O formato é
   representado pelo pequeno desenho; não precisamos de texto dentro dele. */
.ll-fields{grid-template-columns:minmax(0,1.65fr) minmax(72px,.8fr);gap:8px}
.ll-fmt{min-height:44px;padding:6px 8px 6px 10px;border-radius:11px;background:#fffdfb}
.ll-fmt .llprev{flex:1;justify-content:center}
.ll-fmt .llprev-dot{width:9px;height:9px}
.ll-fmt .ll-caret{width:9px;height:16px;opacity:.45}

/* Folha de escolha: duas opções, só grafismo. O nome fica no aria-label/title
   para acessibilidade, mas não polui visualmente a escolha. */
.fmt-lista{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
.fmt-opt{min-height:92px;padding:12px 10px;justify-content:center;border-radius:15px}
.fmt-opt .llprev{width:auto;min-width:100px;justify-content:center;gap:5px 7px}
.fmt-opt .llprev-dot{width:13px;height:13px}
.fmt-opt .fmt-tx{display:none}
.fmt-opt .fmt-ok{position:absolute;width:20px;right:8px;top:8px;font-size:15px}
.fmt-opt{position:relative}
.fmt-opt.on{background:linear-gradient(180deg,#fff,#f9edf1);border-width:1.5px}

/* O cartão deixa de parecer uma lista de formulários e passa a sugerir um
   móvel real: postes laterais muito subtis e madeira contínua. */
.mprat{padding:0 9px;margin-top:7px}
.mprat-layout{gap:5px;padding:0 8px;margin-top:calc(var(--slot,34px) * .08);max-width:760px}
.mp-lbl{max-width:58px;font-size:8px;letter-spacing:.35px}
.mp-fio{opacity:.18}
.mp-esp{min-width:3px}

/* Fila: uma régua de madeira fina, com os pontos a assentarem nela. */
.est-fila{padding:calc(var(--slot) * .10 + 2px) 0 calc(var(--slot) * .18);
  border:0;border-radius:0;background:none;box-shadow:none;position:relative}
.est-fila .msdot{background:var(--vh);border-color:var(--vh);color:#fff;box-shadow:0 2px 4px rgba(78,18,40,.22);z-index:2}
.est-fila .msdot.vazia{background:#fffdfb;border:1.5px dashed #c9a1af;color:var(--vh);box-shadow:none}

/* Sobrepostos: duas linhas compactas, como garrafas realmente empilhadas,
   com a madeira visível sobretudo nas extremidades. */
.est-sobrepostos{padding:calc(var(--slot) * .04) 0 calc(var(--slot) * .13);
  border:0;border-radius:0;background:none;box-shadow:none;position:relative;row-gap:calc(var(--slot) * .015)}
.est-sobrepostos .msdot{background:var(--vh);border-color:var(--vh);color:#fff;box-shadow:0 2px 4px rgba(78,18,40,.22);z-index:2}
.est-sobrepostos .msdot.vazia{background:#fffdfb;border:1.5px dashed #c9a1af;color:var(--vh);box-shadow:none}

/* Ziguezague: quando o renderer já fornece a régua ondulada, reforçamos a
   leitura de "berços" sem tocar na geometria calculada pelo JS. */
.est-regua .msdot{background:var(--vh);border-color:var(--vh);color:#fff;box-shadow:0 2px 4px rgba(78,18,40,.22)}
.est-regua .msdot.vazia{background:#fffdfb;border:1.5px dashed #c9a1af;color:var(--vh);box-shadow:none}

/* A grelha de locais passa a ser mais arejada e mais próxima de um desenho
   técnico/minimalista de uma garrafeira. */
.ml{border-radius:20px;padding-bottom:6px;box-shadow:0 8px 24px -14px rgba(78,18,40,.30)}
.ml-bar{padding:5px 7px;background:linear-gradient(180deg,#fffdfb,var(--bg));}
.ml-nav{width:30px;height:30px;font-size:21px;box-shadow:none;background:#fffdfb}
.ml-t h3{font-size:16px}
.ml-sub{font-size:11.5px;margin-top:0}
.ml-dots{gap:5px;padding:5px 0 0}
.ml-dot{width:6px;height:6px}
.ml-dot.on{width:15px}
.ml-leg{font-size:9px;padding:6px 10px 0;gap:3px 12px}
.ml-leg i{width:11px;height:11px}

/* Pequena moldura de madeira apenas na zona das prateleiras. Não interfere
   nos cliques porque é background, não elemento sobreposto. */
#mapa .mprat{position:relative}
#mapa .mprat::before{content:"";position:absolute;left:2px;right:2px;top:0;bottom:0;pointer-events:none;border-left:3px solid rgba(185,157,112,.20);border-right:3px solid rgba(185,157,112,.20);border-radius:10px}

@media(max-width:460px){
  .fmt-opt{min-height:82px}
  .fmt-opt .llprev{min-width:82px}
  .fmt-opt .llprev-dot{width:11px;height:11px}
  .mprat{padding:0 5px}
  .mprat-layout{padding:0 5px}
  .mp-lbl{max-width:48px;font-size:7.5px}
}
