/* Paleta em tokens — nenhuma cor de interface literal fora daqui.

   O escuro é o tema de omissão de propósito: isto é um configurador de cores,
   e chrome escuro deixa a cor da peça ser julgada sem competir com a
   interface (é o que Figma/Blender/Photoshop fazem). O claro fica acessível
   em :root[data-tema="claro"] — este projeto já mudou de ideias uma vez sobre
   o tema, e assim a próxima mudança custa estas linhas e não as 105 que
   estavam espalhadas pelo ficheiro.

   EXCEÇÃO DELIBERADA: --palco-bg fica CLARO nos dois temas. O editor 2D
   desenha as peças sem fundo próprio (aparecem "soltas" sobre a página) e o
   contorno delas é escuro — num palco escuro, uma peça escura desaparecia,
   que é exatamente o bug que o contorno existe para evitar, ao contrário.
   Escurecer o palco é uma decisão à parte e leva o contorno atrás
   (construirContornos em js/estado.js) e o fundo da cena 3D (cena3d.js). */
:root {
    /* A LISTA aberta de um <select> é desenhada pelo sistema, não por nós: com
       o chrome escuro mas sem isto, o browser abria-a com fundo claro e usava
       a nossa cor de texto (clara) lá dentro — texto branco em fundo branco,
       ilegível. Também acerta scrollbars e campos nativos de uma assentada. */
    color-scheme: dark;

    --accent: #6c5ce7;
    --accent-hover: #7d6ff0;
    --accent-fraco: rgba(108, 92, 231, .28);
    --accent-fraco-2: rgba(108, 92, 231, .18);
    --sobre-accent: #ffffff;
    /* O --accent como TEXTO sobre fundos escuros/fracos só dá 3,0:1 — abaixo
       dos 4,5:1 exigidos. Este tom (accent + ~24% de branco) dá 4,6:1 e serve
       só para texto/ícone; o --accent sólido continua a ser fundo de botão,
       que é outro par de contraste. */
    --accent-texto: #8f83ed;

    --bg: #0e0f14;
    --bg-elevado: #171922;
    --bg-sutil: #202331;
    --bg-sutil-2: #262a39;
    --texto: #eef0f5;
    --texto-fraco: rgba(238, 240, 245, .55);
    --texto-fraco-2: #99a1b3;
    --borda: rgba(255, 255, 255, .12);
    --borda-forte: rgba(255, 255, 255, .3);
    --borda-campo: rgba(255, 255, 255, .18);
    --fundo-fraco: rgba(255, 255, 255, .06);
    --fundo-fraco-2: rgba(255, 255, 255, .12);
    --fundo-sobreposto: rgba(0, 0, 0, .75);
    --icone-inativo: rgba(255, 255, 255, .2);
    --xadrez: rgba(255, 255, 255, .07);
    /* halo das miniaturas das peças: separa a peça do cartão quando as duas
       têm tons parecidos — no tema claro era uma peça branca sobre cartão
       branco, no escuro é uma gola preta sobre cartão preto (o mesmo
       problema ao contrário, por isso o halo inverte com o tema) */
    --halo-amostra: rgba(255, 255, 255, .5);

    /* par invertido: botões que no tema claro eram escuros para saltar à
       vista têm de ser claros no tema escuro, pela mesma razão */
    --bg-contraste: #eef0f5;
    --texto-contraste: #16191d;
    --borda-contraste: rgba(0, 0, 0, .14);
    --borda-contraste-forte: rgba(0, 0, 0, .38);

    --perigo: #ff6b6b;
    --perigo-claro: #ff8a80;
    --perigo-forte: #c62828;
    --perigo-fraco: rgba(255, 107, 107, .12);

    --scrim: rgba(0, 0, 0, .6);
    --overlay-fundo: rgba(14, 15, 20, .96);
    --sombra: 0 6px 24px rgba(0, 0, 0, .55);
    --sombra-suave: 0 3px 10px rgba(0, 0, 0, .4);
    --sombra-modal: 0 12px 48px rgba(0, 0, 0, .6);
    --sombra-menu: 0 12px 36px rgba(0, 0, 0, .5);

    --palco-bg: #ecedf1;
}

:root[data-tema="claro"] {
    --accent-hover: #5b4bd6;
    --accent-fraco: rgba(108, 92, 231, .12);
    --accent-fraco-2: rgba(108, 92, 231, .08);
    --accent-texto: #5b4bd6;

    --bg: #f6f7f9;
    --bg-elevado: #ffffff;
    --bg-sutil: #f2f1fc;
    --bg-sutil-2: #f2f4f7;
    --texto: #16191d;
    --texto-fraco: rgba(22, 25, 29, .5);
    --texto-fraco-2: #8a9199;
    --borda: rgba(0, 0, 0, .1);
    --borda-forte: rgba(0, 0, 0, .22);
    --borda-campo: rgba(0, 0, 0, .18);
    --fundo-fraco: rgba(0, 0, 0, .05);
    --fundo-fraco-2: rgba(0, 0, 0, .1);
    --fundo-sobreposto: rgba(20, 26, 34, .75);
    --icone-inativo: rgba(0, 0, 0, .15);
    --xadrez: rgba(0, 0, 0, .06);
    --halo-amostra: rgba(0, 0, 0, .35);

    --bg-contraste: #232b37;
    --texto-contraste: #e8ecf1;
    --borda-contraste: rgba(255, 255, 255, .12);
    --borda-contraste-forte: rgba(255, 255, 255, .35);

    --perigo: #b3261e;
    --perigo-fraco: rgba(179, 38, 30, .08);

    --scrim: rgba(22, 25, 29, .45);
    --overlay-fundo: rgba(255, 255, 255, .96);
    --sombra: 0 6px 24px rgba(22, 25, 29, .1);
    --sombra-suave: 0 3px 10px rgba(0, 0, 0, .06);
    --sombra-modal: 0 12px 48px rgba(0, 0, 0, .25);
    --sombra-menu: 0 12px 36px rgba(0, 0, 0, .18);
}

html, body {
    margin: 0;
    /* Arrastar no palco ou nos painéis fazia o iOS entrar em seleção de texto
       e pintar tudo de azul, com pegas de seleção por cima do modelo (o
       utilizador mandou capturas). Isto é uma aplicação, não um documento —
       só os campos de texto é que se selecionam (regra a seguir). */
    user-select: none;
    -webkit-user-select: none;
    -webkit-touch-callout: none;
    /* O bloqueio de pinch em painel.js (gesturestart/gesturechange/gestureend)
       só trava o gesto de dois dedos — o duplo-toque do Safari para ampliar é
       outro mecanismo, sem gesture events, e continuava a passar em qualquer
       zona fora do canvas (que já tinha touch-action: none). Isto fecha essa
       lacuna sem tirar o toque simples nem o arrastar. */
    touch-action: manipulation;
    width: 100%;
    height: 100%;
    overflow: hidden;
    background: var(--bg);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
    color: var(--texto);
}

.escondido { display: none !important; }

/* a exceção: escrever num campo tem de continuar a permitir selecionar */
input, textarea, [contenteditable] {
    user-select: text;
    -webkit-user-select: text;
}

/* ------------------------------------------------------------ header */

#topo {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 54px;
    z-index: 10;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 16px;
    box-sizing: border-box;
    background: var(--bg-elevado);
    border-bottom: 1px solid var(--borda);
}

.marca {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--texto);
}

/* Voltar à galeria: entra-se no editor a partir dela, mas o header não tinha
   caminho de volta (o logótipo vai para o site institucional). */
.topo-voltar {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px 6px 8px;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--texto-fraco);
    text-decoration: none;
    background: var(--bg-elevado);
    border: 1px solid var(--borda);
    border-radius: 9px;
}

.topo-voltar:hover { color: var(--texto); background: var(--bg-sutil); }

.topo-voltar svg { width: 14px; height: 14px; flex: none; }

.brand {
    font-size: 17px;
    font-weight: 800;
    letter-spacing: .01em;
    text-decoration: none;
    line-height: 1;
}

.brand-pw { color: var(--texto); }

.brand-dev { color: var(--accent-texto); }

.marca .badge {
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--bg-sutil);
    color: var(--texto-fraco);
    font-size: 10px;
    letter-spacing: .03em;
}

/* seletor de modelo, centrado no header (pedido do mockup) */
.topo-centro {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
}

#sel-modelo {
    font: inherit;
    font-size: 12.5px;
    font-weight: 600;
    padding: 7px 10px;
    border: 1px solid var(--borda);
    border-radius: 9px;
    background: var(--bg-elevado);
    color: var(--texto);
    cursor: pointer;
}

/* Seletor de idioma com bandeiras SVG (partials/seletor-idioma.php) — um
   <details> próprio porque as <option> nativas não aceitam imagens e os
   emojis de bandeira não existem no Windows. Mesmo desenho do #sel-modelo. */
.sel-idioma-caixa { position: relative; }

.sel-idioma-caixa summary {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    list-style: none;
    font: inherit;
    font-size: 12.5px;
    font-weight: 600;
    padding: 7px 8px;
    border: 1px solid var(--borda);
    border-radius: 9px;
    background: var(--bg-elevado);
    color: var(--texto);
    cursor: pointer;
    user-select: none;
}

.sel-idioma-caixa summary::-webkit-details-marker { display: none; }

.sel-idioma-caixa img {
    width: 18px;
    height: 12px;
    border-radius: 2px;
    display: block;
}

.sel-idioma-caixa nav {
    position: absolute;
    right: 0;
    top: calc(100% + 4px);
    z-index: 30;
    min-width: 100%;
    padding: 4px;
    background: var(--bg-elevado);
    border: 1px solid var(--borda);
    border-radius: 9px;
    box-shadow: var(--sombra-modal);
}

.sel-idioma-caixa nav a {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 10px;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--texto);
    text-decoration: none;
    border-radius: 7px;
    white-space: nowrap;
}

.sel-idioma-caixa nav a:hover { background: var(--bg-sutil); }

.sel-idioma-caixa nav a.ativa { color: var(--accent); background: var(--accent-fraco-2); }

.topo-acoes {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* ---- conta (galeria): quem está a usar + sair, no canto do header ---- */
.conta-caixa { position: relative; }

.conta-avatar {
    width: 32px;
    height: 32px;
    display: grid;
    place-items: center;
    padding: 0;
    font: inherit;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .02em;
    color: var(--sobre-accent);
    background: var(--accent);
    border: 0;
    border-radius: 50%;
    cursor: pointer;
}

.conta-avatar:hover { background: var(--accent-hover); }

/* .menu-contexto é position:fixed (nasceu para menus abertos no sítio do
   rato); aqui é um dropdown preso ao avatar, daí o absolute. */
.conta-caixa .menu-contexto {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    min-width: 190px;
}

.conta-nome {
    padding: 5px 8px 7px;
    font-size: 12px;
    font-weight: 700;
    color: var(--texto);
    border-bottom: 1px solid var(--borda);
    margin-bottom: 5px;
}

.conta-caixa .menu-contexto a {
    display: block;
    padding: 7px 8px;
    font-size: 12px;
    color: var(--texto);
    text-decoration: none;
    border-radius: 7px;
}

.conta-caixa .menu-contexto a:hover { background: var(--bg-sutil); }
.conta-caixa .menu-contexto a.perigo { color: var(--perigo); }

.topo-botao {
    font: inherit;
    font-size: 12.5px;
    font-weight: 600;
    padding: 7px 12px;
    border: 1px solid var(--borda);
    border-radius: 9px;
    background: var(--bg-elevado);
    color: var(--texto);
    cursor: pointer;
    white-space: nowrap;
}

.topo-botao:hover { background: var(--bg-sutil); }

.topo-botao.primario {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--sobre-accent);
}

.topo-botao.primario:hover { background: var(--accent-hover); }

.topo-botao:disabled { opacity: .75; cursor: default; }

/* ícones SVG inline (substituem os emojis) */
.ico {
    width: 15px;
    height: 15px;
    vertical-align: -2px;
    flex-shrink: 0;
}

.camada .camada-acoes button .ico {
    width: 12px;
    height: 12px;
    vertical-align: -1px;
}

/* --------------------------------------------- editor de moldes (principal) */

/* Largura do painel esquerdo (rail + conteúdo: Partes, Cores, Tecido…) e do
   painel de camadas à direita — usadas para alinhar tudo o resto da faixa
   central (alternador, ferramentas, palco) sem repetir números mágicos em
   cada regra. */
:root {
    --painel-largura: 336px;
    --camadas-largura: 260px;
    --margem: 14px;
    /* coluna do chat da IA em ecrã largo (ver "chat da IA ancorado"): a
       largura é fixa, a faixa que ela ROUBA ao palco é que liga/desliga. */
    --ia-largura: 340px;
    --ia-faixa: 0px;
}

/* top mínimo (só a folga do header) — alternador-vista e a barra de
   ferramentas são overlays A SÉRIO agora (position:fixed + z-index por
   cima), não reservam faixa própria, por isso o palco/editor podem começar
   quase logo abaixo do header. */
#editor-principal {
    /* claro de propósito, mesmo no tema escuro — ver a nota do --palco-bg */
    background: var(--palco-bg);
    position: fixed;
    top: 68px;
    left: calc(var(--painel-largura) + var(--margem) * 2);
    right: calc(var(--camadas-largura) + var(--ia-faixa) + var(--margem) * 2);
    bottom: var(--margem);
}

/* Vista principal 3D: ocupa a mesma faixa que o editor 2D — ver painel.js
   (aplicarVista) e cena3d.js (moverPalcoPara/redimensionar, reaproveitados
   tal e qual da miniatura/modal, sem duplicar a cena three.js).
   #palco-principal-caixa preenche o retângulo TODO (não fica preso a um
   quadrado central) — a câmara tem FOV vertical fixo, por isso um retângulo
   mais largo só revela mais FOV horizontal, sem encolher a peça. */
#palco-principal {
    /* claro de propósito, mesmo no tema escuro — ver a nota do --palco-bg */
    background: var(--palco-bg);
    position: fixed;
    top: 68px;
    left: calc(var(--painel-largura) + var(--margem) * 2);
    right: calc(var(--camadas-largura) + var(--ia-faixa) + var(--margem) * 2);
    bottom: var(--margem);
    display: flex;
    align-items: center;
    justify-content: center;
}

#palco-principal-caixa { width: 100%; height: 100%; }

/* Controlo manual de girar/zoom do 3D — soma-se ao arrastar do rato/dedo
   (OrbitControls), não substitui: útil em ecrãs onde arrastar é incómodo,
   ou para precisão. #palco-principal já é a base position:fixed. */
#controlos-3d {
    position: absolute;
    left: 50%;
    bottom: 16px;
    transform: translateX(-50%);
    width: min(320px, 86%);
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 8px 12px;
    background: var(--bg-elevado);
    border: 1px solid var(--borda);
    border-radius: 14px;
    box-shadow: var(--sombra);
    z-index: 5;
}

.controlos-3d-linha1 {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

#bt-girar-3d {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 5px 8px;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    color: var(--texto);
    background: transparent;
    border: 0;
    border-radius: 999px;
    cursor: pointer;
}

#bt-girar-3d:hover { background: var(--bg-sutil); }

#bt-girar-3d svg { width: 15px; height: 15px; fill: currentColor; }

#bt-girar-3d.ativo { color: var(--accent-texto); }

.controlos-3d-zoom { display: flex; gap: 2px; flex-shrink: 0; }

.controlos-3d-zoom button {
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
    line-height: 1;
    border: 0;
    border-radius: 999px;
    background: var(--bg-sutil);
    color: var(--texto);
    cursor: pointer;
}

.controlos-3d-zoom button:hover { background: var(--accent-fraco); color: var(--accent); }

#slider-girar-3d {
    width: 100%;
    accent-color: var(--accent);
    cursor: pointer;
}

/* Arrastar vs girar: fica na barra principal (fora do "Mais opções") porque
   troca o que o rato/dedo faz no palco — é gesto, não aparência. */
.controlos-3d-linha-modo {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 2px 2px 0;
    cursor: pointer;
}

.interruptor-3d {
    appearance: none;
    -webkit-appearance: none;
    flex-shrink: 0;
    width: 32px;
    height: 18px;
    margin: 0;
    border-radius: 999px;
    background: var(--bg-sutil);
    border: 1px solid var(--borda);
    position: relative;
    cursor: pointer;
    transition: background .15s;
}

.interruptor-3d::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--texto-fraco);
    transition: transform .15s, background .15s;
}

.interruptor-3d:checked { background: var(--accent); border-color: var(--accent); }

.interruptor-3d:checked::after { transform: translateX(14px); background: #fff; }

/* "Mais opções": tudo o que ajusta a APARÊNCIA da cena (sombra, luz, tecido,
   fundo) vive colapsado — a barra flutuante é para girar/zoom, que é o que se
   usa a toda a hora. <details> nativo: sem JS para abrir e fechar. */
#controlos-3d-mais > summary {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 2px;
    font-size: 12px;
    font-weight: 600;
    color: var(--texto-fraco);
    cursor: pointer;
    list-style: none;
}

#controlos-3d-mais > summary::-webkit-details-marker { display: none; }

#controlos-3d-mais > summary:hover { color: var(--texto); }

#controlos-3d-mais > summary svg { width: 14px; height: 14px; }

/* A seta é desenhada aqui (o marcador nativo foi escondido acima) para poder
   rodar ao abrir, como nos outros colapsáveis do painel. */
#controlos-3d-mais > summary::after {
    content: '';
    margin-left: auto;
    width: 6px;
    height: 6px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(-45deg);
    transition: transform .15s;
}

#controlos-3d-mais[open] > summary::after { transform: rotate(45deg); }

.controlos-3d-linha-op {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 4px;
}

.controlos-3d-rotulo {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    /* os rótulos têm larguras diferentes ("Luz"/"Velocidade") e sem isto cada
       slider começava num sítio */
    min-width: 78px;
    font-size: 12px;
    font-weight: 600;
    color: var(--texto-fraco);
}

.controlos-3d-rotulo svg { width: 14px; height: 14px; }

#controlos-3d-mais input[type="range"] {
    flex: 1;
    min-width: 0;
    accent-color: var(--accent);
    cursor: pointer;
}

#cor-fundo-3d {
    flex: 1;
    min-width: 0;
    height: 24px;
    padding: 0;
    border: 1px solid var(--borda);
    border-radius: 6px;
    background: none;
    cursor: pointer;
}

.controlos-3d-linha-repor { display: flex; justify-content: flex-end; margin-top: 6px; }

#bt-repor-aparencia {
    padding: 4px 10px;
    font: inherit;
    font-size: 11px;
    font-weight: 600;
    color: var(--texto-fraco);
    background: var(--bg-sutil);
    border: 0;
    border-radius: 999px;
    cursor: pointer;
}

#bt-repor-aparencia:hover { color: var(--accent); background: var(--accent-fraco); }

/* Faixa flutuante POR CIMA do palco (overlay a sério — não empurra o
   conteúdo, só se sobrepõe graças ao z-index): alternador 2D/3D e lados do
   modelo na MESMA linha, centrados, com quebra automática quando a faixa é
   estreita de mais (telemóvel). O padding em cima afasta as pílulas do
   header — coladas, liam-se como parte dele. */
#barra-vistas {
    position: fixed;
    top: 62px;
    left: calc(var(--painel-largura) + var(--margem) * 2);
    right: calc(var(--camadas-largura) + var(--ia-faixa) + var(--margem) * 2);
    z-index: 9;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding-top: 20px;
    pointer-events: none;
}

#alternador-vista {
    display: flex;
    justify-content: center;
    pointer-events: none;
}

#alternador-vista .alt-btns { pointer-events: auto; }

#alternador-vista > .alt-btns {
    display: flex;
    gap: 2px;
    background: var(--bg-elevado);
    border: 1px solid var(--borda);
    border-radius: 999px;
    padding: 3px;
    box-shadow: var(--sombra);
}

.alt-btn {
    font: inherit;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .02em;
    padding: 6px 16px;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: var(--texto-fraco);
    cursor: pointer;
}

.alt-btn:hover { color: var(--texto); }

.alt-btn.ativa { background: var(--accent); color: var(--sobre-accent); }

/* Os moldes vivem soltos sobre o fundo da página: o canvas ocupa o palco
   inteiro, transparente e sem moldura — o desenho recorta as peças pelas
   máscaras, por isso não há "cartão" à volta. */
#canvas-moldes {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    background: transparent;
    touch-action: none;
}

/* Rail vertical encostado ao canto superior esquerdo do palco. Já foi uma
   coluna, depois uma barra horizontal centrada logo abaixo do alternador —
   e aí ficavam duas pílulas empilhadas mesmo por cima dos moldes, que é o
   que se quer ver. Ao canto, o meio do palco fica livre e a barra deixa de
   disputar a faixa com o alternador (que continua centrado). */
.editor-ferramentas {
    position: fixed;
    top: 62px;
    left: calc(var(--painel-largura) + var(--margem) * 2 + 10px);
    right: auto;
    z-index: 7;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 4px;
    padding: 6px;
    box-sizing: border-box;
    background: var(--bg-elevado);
    border: 1px solid var(--borda);
    /* 999px num rail alto arredondava demais e comia o rótulo AUTO no topo */
    border-radius: 20px;
    box-shadow: var(--sombra);
    width: fit-content;
    margin: 0;
}

.ferramenta {
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 999px;
    background: transparent;
    cursor: pointer;
    padding: 0;
}

.ferramenta svg {
    width: 18px;
    height: 18px;
    fill: var(--texto-fraco);
}

.ferramenta:hover:not(:disabled) { background: var(--bg-sutil); }

.ferramenta.ativa { background: var(--accent-fraco); }

/* modo único "auto": seta com o rótulo por baixo */
.ferramenta-auto {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;
    width: 44px;
}

.fer-rotulo {
    font-size: 7.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--texto-fraco);
}

.ferramenta-auto.ativa .fer-rotulo { color: var(--accent); }

.ferramenta.ativa svg { fill: var(--accent); }

.ferramenta:disabled { cursor: default; }

.ferramenta:disabled svg { fill: var(--icone-inativo); }

/* rail vertical no desktop → o divisor é uma linha horizontal */
.fer-divisor {
    width: 22px;
    height: 1px;
    margin: 3px 0;
    background: var(--borda);
}

/* ------------------------------------------------ painel de edição (esquerda) */

/* #nav-secoes é irmão de #painel (não filho) — assim consegue continuar
   visível/fixo mesmo quando #painel está colapsado ou (no mobile) só uma
   secção de cada vez está aberta; um pai com display:none esconderia um
   filho position:fixed junto, não há como escapar disso em CSS. */
#nav-secoes {
    position: fixed;
    top: 66px;
    left: var(--margem);
    bottom: var(--margem);
    width: 64px;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    padding: 14px 6px;
    background: var(--bg-elevado);
    border: 1px solid var(--borda);
    border-radius: 14px;
    box-shadow: var(--sombra);
    z-index: 6;
    overflow-y: auto;
}

#painel {
    position: fixed;
    top: 66px;
    left: calc(var(--margem) + 64px + 8px);
    bottom: var(--margem);
    width: calc(var(--painel-largura) - 64px - 8px);
    box-sizing: border-box;
    background: var(--bg-elevado);
    border: 1px solid var(--borda);
    border-radius: 14px;
    box-shadow: var(--sombra);
    color: var(--texto);
    z-index: 6;
    /* visible e não hidden: a pega de colapsar vive a cavalo na borda
       (right/left: -12px) e com overflow:hidden ficava cortada ao meio —
       via-se meia lua e não um botão (chamado #117). Quem tem de cortar é o
       conteúdo, e esse já rola dentro de #painel-conteudo. */
    overflow: visible;
}

#nav-secoes button {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    padding: 8px 2px;
    font: inherit;
    border: 0;
    border-radius: 10px;
    background: transparent;
    color: var(--texto-fraco);
    cursor: pointer;
}

#nav-secoes button svg { width: 18px; height: 18px; fill: currentColor; }

#nav-secoes button span { font-size: 9px; font-weight: 600; }

#nav-secoes button:hover { background: var(--bg-sutil); }

#nav-secoes button.ativa { color: var(--accent-texto); background: var(--accent-fraco-2); }

/* Botão de encolher/expandir cada painel lateral — poking pra fora do
   próprio cartão (não fica preso a #painel-conteudo, senão desaparecia
   junto com o resto quando colapsado e não haveria como reabrir). Encolher
   só muda --painel-largura/--camadas-largura (ver :root mais acima) — como
   toda a faixa central é calc() em cima dessas variáveis, o palco/editor
   crescem automaticamente para ocupar o espaço libertado. */
.bt-colapsar {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 24px;
    height: 24px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Contraste próprio, não emprestado do painel: colapsado, o cartão fica
       transparente e a pega passa a estar sozinha em cima do fundo da página
       — com o tom do painel (quase o do fundo) parecia ter desaparecido
       (chamado #117). */
    background: var(--bg-sutil);
    border: 1px solid var(--borda-forte);
    border-radius: 50%;
    box-shadow: var(--sombra);
    color: var(--texto);
    cursor: pointer;
    z-index: 8;
}

.bt-colapsar svg { width: 14px; height: 14px; }

.bt-colapsar:hover { background: var(--accent); border-color: var(--accent); color: var(--sobre-accent); }

.bt-colapsar-dir { right: -12px; }

.bt-colapsar-esq { left: -12px; }

/* peça girada 180° quando o painel está colapsado (aponta para o lado
   oposto, "puxa para abrir" em vez de "empurra para fechar") */
.bt-colapsar.colapsado svg { transform: rotate(180deg); }

body.painel-colapsado { --painel-largura: 64px; }
body.painel-colapsado #painel-conteudo { display: none; }

body.camadas-colapsado { --camadas-largura: 0px; }
body.camadas-colapsado #painel-camadas > *:not(.bt-colapsar) { display: none; }
body.camadas-colapsado #painel-camadas { width: 26px; padding: 0; border: 0; box-shadow: none; background: transparent; }
body.camadas-colapsado .bt-colapsar-esq { left: 0; }

#painel-conteudo {
    height: 100%;
    min-width: 0;
    padding: 16px 14px;
    box-sizing: border-box;
    overflow-y: auto;
    overflow-x: hidden;
    display: flex;
    flex-direction: column;
}

/* Num flex column com overflow, os filhos ENCOLHEM antes de haver scroll —
   o menu do "Adicionar imagem" chegava a ficar com 2px com zoom/ecrã baixo.
   Sem encolher, o painel rola como deve ser. */
#painel-conteudo > * {
    flex-shrink: 0;
}

/* títulos de secção pequenos, em maiúsculas — como nos configuradores a sério */
.painel-titulo {
    font-size: 10.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .09em;
    color: var(--texto-fraco);
    margin-bottom: 6px;
}

.painel-titulo.seccao {
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--borda);
}

/* cabeçalho do bloco contextual (nome da peça/imagem + fechar) */
.painel-cabecalho {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 10px;
    padding: 8px 10px;
    background: var(--bg-sutil);
    border: 1px solid var(--borda);
    border-radius: 10px;
}

.cabecalho-nome {
    flex: 1;
    min-width: 0;
    font-size: 13px;
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* O nome da peça é um <select>: dentro do cabeçalho tem de parecer texto, com
   só a setinha a denunciar que se pode trocar ali mesmo. */
select.cabecalho-nome {
    appearance: none;
    -webkit-appearance: none;
    /* não estica: com flex:1 a setinha ia parar ao pé do × e deixava de se ler
       como "isto abre uma lista" */
    flex: 0 1 auto;
    max-width: 100%;
    padding: 2px 20px 2px 6px;
    font-family: inherit;
    color: var(--texto);
    background: transparent no-repeat right center / 12px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23888' d='M7 10l5 5 5-5z'/%3E%3C/svg%3E");
    border: 0;
    border-radius: 6px;
    cursor: pointer;
}

select.cabecalho-nome:hover { background-color: var(--fundo-fraco-2); }

/* no dedo, 21px de altura não se acerta — o cabeçalho tem espaço de sobra */
@media (pointer: coarse) {
    select.cabecalho-nome { min-height: 34px; }
}

.cabecalho-fechar {
    width: 22px;
    height: 22px;
    font-size: 14px;
    line-height: 1;
    color: var(--texto-fraco);
    background: var(--fundo-fraco);
    border: 0;
    border-radius: 6px;
    cursor: pointer;
    flex: 0 0 auto;
}

.cabecalho-fechar:hover { background: var(--fundo-fraco-2); }

.painel-nota {
    padding: 10px 4px;
    font-size: 11.5px;
    line-height: 1.5;
    color: var(--texto-fraco);
    text-align: center;
}

.painel-nota b { color: var(--texto); }

/* card "Dica Pro" — copy estática, sem link de destino ainda */
.dica-pro {
    display: flex;
    gap: 10px;
    margin-top: 18px;
    padding: 12px;
    background: var(--bg-sutil);
    border: 1px solid var(--borda);
    border-radius: 10px;
}

.dica-pro-icone { font-size: 18px; line-height: 1; }

.dica-pro-titulo { font-size: 12px; font-weight: 700; margin-bottom: 3px; }

.dica-pro p { margin: 0; font-size: 11.5px; line-height: 1.4; color: var(--texto-fraco); }

/* propriedades da imagem selecionada */
.linha-botoes {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.botao-accao {
    width: 100%;
    padding: 8px 10px;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    text-align: left;
    color: var(--texto-contraste);
    background: var(--bg-contraste);
    border: 1px solid var(--borda-contraste);
    border-radius: 9px;
    cursor: pointer;
    box-sizing: border-box;
}

.botao-accao:hover { border-color: var(--borda-contraste-forte); }

.botao-accao.perigo { color: var(--perigo-claro); }

.botao-accao.perigo:hover { border-color: var(--perigo-claro); }

/* propriedades numéricas da imagem selecionada (posição/tamanho/rotação/opacidade) */
.painel-propriedades { margin-top: 4px; }

.prop-linha {
    display: flex;
    gap: 10px;
    margin-bottom: 8px;
}

/* Gaveta "Avançado": o que só interessa a quem quer precisão ao píxel fica
   fechado por omissão, no mesmo sítio onde estava. */
.grupo-avancado { margin-top: 2px; }

.grupo-avancado > summary {
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 6px 2px;
    font-size: 10.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--texto-fraco);
    cursor: pointer;
    list-style: none;
}

.grupo-avancado > summary::-webkit-details-marker { display: none; }

.grupo-avancado > summary:hover { color: var(--texto); }

.grupo-avancado > summary svg {
    width: 13px;
    height: 13px;
    fill: none;
    stroke: currentColor;
    stroke-width: 2.4;
    stroke-linecap: round;
    transition: transform .15s;
}

.grupo-avancado[open] > summary svg { transform: rotate(90deg); }

/* setas de passo fixo (chamado #110) — alvos de 34px, à medida do dedo */
.prop-setas {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 8px;
}

.prop-setas-rotulo {
    flex: 1;
    font-size: 11px;
    font-weight: 600;
    color: var(--texto-fraco);
}

.prop-setas button {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border: 1px solid var(--borda);
    border-radius: 8px;
    background: var(--bg-sutil);
    color: var(--texto-fraco);
    cursor: pointer;
}

.prop-setas button:hover { border-color: var(--borda-forte); color: var(--texto); }

.prop-setas button:active { background: var(--fundo-fraco); }

.prop-setas button svg {
    width: 16px;
    height: 16px;
    fill: none;
    stroke: currentColor;
    stroke-width: 2.2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.prop-campo {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.prop-campo > span {
    font-size: 10.5px;
    font-weight: 600;
    color: var(--texto-fraco);
}

.prop-campo input[type="number"] {
    width: 100%;
    padding: 6px 8px;
    font: inherit;
    font-size: 12.5px;
    color: var(--texto);
    background: var(--bg-sutil);
    border: 1px solid var(--borda);
    border-radius: 8px;
    box-sizing: border-box;
}

.prop-campo input[type="number"]:focus { outline: none; border-color: var(--accent); }

.prop-opacidade { display: flex; align-items: center; gap: 8px; min-width: 0; }

/* min-width:0 obrigatório: um <input type="range"> como flex item nunca
   encolhe abaixo da largura própria do browser (~129px) e empurrava a linha
   Rotação/Opacidade para fora do painel (que só tem ~230px úteis). */
.prop-opacidade input[type="range"] { flex: 1; min-width: 0; accent-color: var(--accent); cursor: pointer; }

.prop-opacidade span { font-size: 11.5px; font-weight: 600; color: var(--texto-fraco); min-width: 32px; text-align: right; }

/* Presença: quem está no mesmo design. Sobrepostos como nos editores
   colaborativos — ocupam pouco na barra e lê-se logo que são pessoas. */
#presenca { display: flex; align-items: center; }

.presenca-avatar {
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    margin-right: -7px;
    border: 2px solid var(--bg-elevado);
    border-radius: 50%;
    background: var(--accent);
    color: var(--sobre-accent);
    font: 700 10.5px/1 -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
    letter-spacing: .02em;
    cursor: default;
}

/* O próprio separador, para a pessoa perceber qual é ela (a mesma conta aberta
   duas vezes aparece duas vezes — é de propósito). */
.presenca-avatar.eu { background: var(--fundo-fraco-2); color: var(--texto-fraco); }

/* botão "Mais ações" (Limpar) — menos exposto que Guardar/Exportar de propósito */
.menu-mais-caixa { position: relative; }

.menu-mais-caixa .menu-contexto {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    left: auto;
    min-width: 160px;
}

/* `left:auto; right:0` faz a largura ser shrink-to-fit medida a partir do
   contentor relativo — que aqui é só o botão ⋮. Sem um mínimo explícito as
   quatro bandeiras cairiam uma por linha. 260px chegam para as quatro em
   linha; a partir daí o flex-wrap trata do resto. */
#menu-mais-acoes {
    min-width: 260px;
    max-width: calc(100vw - 20px);
}

/* linha de cor: bola com a cor atual + hex + conta-gotas (abre o picker) */
#cor-linha {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 8px;
    padding: 8px 10px;
    background: var(--bg-sutil);
    border: 1px solid var(--borda);
    border-radius: 10px;
    cursor: pointer;
}

#cor-linha:hover { border-color: var(--borda-forte); }

#cor-bola {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 1px solid var(--borda-forte);
    flex-shrink: 0;
}

/* Input de cor real e TOCÁVEL por cima da LINHA INTEIRA (em vez de
   width:0/height:0 + clique programático): em iOS/Android, um
   <input type="color"> com tamanho zero muitas vezes não abre o seletor
   nativo quando "clicado" via JS — só um toque real num elemento com área
   funciona em todos os browsers móveis. Cobria só a bola e no telemóvel
   tocar no resto da linha não abria nada (chamado #111); agora qualquer
   ponto da linha é o próprio input. O conta-gotas fica por cima (z-index)
   para continuar clicável. */
.input-cor-alvo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    border: 0;
    padding: 0;
    cursor: pointer;
}

#bt-conta-gotas { position: relative; z-index: 1; }

#cor-hex {
    flex: 1;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: .03em;
    color: var(--texto);
}

#bt-conta-gotas {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: var(--texto-fraco-2);
    cursor: pointer;
}

#bt-conta-gotas:hover { background: rgba(0, 0, 0, .06); color: var(--texto); }

/* linha de cor da estampa — mesmo desenho de #cor-linha, ids próprios porque
   coexistem no mesmo painel quando uma peça com estampa está selecionada */
#cor-estampa-linha {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 8px;
    padding: 8px 10px;
    background: var(--bg-sutil);
    border: 1px solid var(--borda);
    border-radius: 10px;
    cursor: pointer;
}

#cor-estampa-linha:hover { border-color: var(--borda-forte); }

#cor-estampa-bola {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 1px solid var(--borda-forte);
    flex-shrink: 0;
}

#cor-estampa-hex {
    flex: 1;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: .03em;
    color: var(--texto);
}

/* estampas prontas (padrões procedurais aplicados à peça selecionada) */
#estampas, #tecidos {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 6px;
    margin-top: 6px;
}

.estampa {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    min-width: 0;
    padding: 5px 4px;
    background: var(--bg-sutil);
    border: 2px solid var(--borda);
    border-radius: 9px;
    cursor: pointer;
    font-family: inherit;
}

.estampa canvas, .estampa img {
    width: 100%;
    height: 34px;
    border-radius: 5px;
    display: block;
    object-fit: cover;
}

.estampa span {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 9px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--texto-fraco);
}

.estampa:hover { border-color: var(--borda-forte); }

.estampa.ativa {
    border-color: var(--accent);
    box-shadow: 0 0 0 1px var(--accent) inset;
}

.botao-largo {
    width: 100%;
    margin-top: 8px;
    padding: 9px 10px;
    font: inherit;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--sobre-accent);
    background: var(--accent);
    border: 1px solid var(--accent);
    border-radius: 9px;
    cursor: pointer;
    box-sizing: border-box;
}

.botao-largo:hover { background: var(--accent-hover); }

/* variante discreta: ação secundária dentro de uma secção do painel */
.botao-largo.fantasma {
    color: var(--texto-fraco-2);
    background: transparent;
    border-color: var(--borda-campo);
}

.botao-largo.fantasma:hover {
    color: var(--texto);
    background: var(--fundo-fraco);
}

/* modal "Adicionar imagem": cards de origem + zona de largar/colar */
#modal-adicionar {
    position: fixed;
    inset: 0;
    z-index: 32;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--scrim);
}

.cartoes-adicionar {
    display: grid;
    /* dois cartões desde que o texto ganhou botão próprio (chamado #107) */
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
    margin-bottom: 10px;
}

.cartoes-adicionar button {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 14px 10px;
    font: inherit;
    color: var(--texto);
    background: var(--bg-sutil);
    border: 1px solid var(--borda);
    border-radius: 12px;
    cursor: pointer;
    text-align: center;
}

.cartoes-adicionar button:hover { border-color: var(--accent); background: var(--accent-fraco-2); }

.cartao-icone svg { width: 26px; height: 26px; color: var(--accent); }

.cartao-titulo { font-size: 13px; font-weight: 700; }

.cartao-desc { font-size: 11px; color: var(--texto-fraco-2); line-height: 1.35; }

#zona-colar {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    padding: 18px 10px;
    border: 2px dashed var(--borda-forte);
    border-radius: 12px;
    outline: none;
    cursor: copy;
}

#zona-colar:focus,
#zona-colar.arrastando { border-color: var(--accent); background: rgba(108, 92, 231, .06); }

/* No telemóvel as descrições dos cartões ocupavam 4 linhas cada uma e
   empurravam a biblioteca para fora do ecrã; e arrastar/colar não existe no
   toque, por isso a zona de largar era só espaço perdido. */
@media (max-width: 900px) {
    .cartoes-adicionar button { padding: 10px 6px; gap: 2px; }

    .cartoes-adicionar { gap: 8px; margin-bottom: 8px; }

    .cartao-icone svg { width: 22px; height: 22px; }

    .cartao-titulo { font-size: 12px; }

    .cartao-desc { display: none; }
}

@media (pointer: coarse) {
    #zona-colar { display: none; }
}

/* modal "Adicionar texto" — mesmo desenho do modal-adicionar/modal-ia */
#modal-texto,
#modal-partilha {
    position: fixed;
    inset: 0;
    z-index: 32;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--scrim);
}

/* O link é para ser copiado, não lido de relance: fonte de largura fixa e
   seleção fácil. Fica em duas linhas se não couber, em vez de cortar. */
#partilha-url {
    width: 100%;
    padding: 9px 10px;
    margin-bottom: 10px;
    font: 12px/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    color: var(--texto);
    background: var(--fundo-campo, transparent);
    border: 1px solid var(--borda-campo);
    border-radius: 8px;
    box-sizing: border-box;
    outline: none;
}

#modal-partilha .botao-largo + .botao-largo {
    margin-top: 8px;
}

#texto-conteudo {
    width: 100%;
    padding: 8px 10px;
    font: inherit;
    font-size: 12.5px;
    border: 1px solid var(--borda-campo);
    border-radius: 8px;
    box-sizing: border-box;
    outline: none;
    resize: vertical;
    min-height: 44px;
    margin-bottom: 10px;
}

#texto-conteudo:focus { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(108, 92, 231, .15); }

#texto-fonte {
    display: block;
    width: 100%;
    padding: 8px 10px;
    font: inherit;
    font-size: 12.5px;
    border: 1px solid var(--borda-campo);
    border-radius: 8px;
    box-sizing: border-box;
    background: var(--bg-elevado);
    margin-bottom: 10px;
}

#texto-fonte:focus { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(108, 92, 231, .15); outline: none; }

#texto-cor-linha {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 12px;
    padding: 8px 10px;
    background: var(--bg-sutil);
    border: 1px solid var(--borda);
    border-radius: 10px;
    cursor: pointer;
}

#texto-cor-linha:hover { border-color: var(--borda-forte); }

#texto-cor-bola {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    border: 1px solid var(--borda-campo);
    background: #000;
    flex-shrink: 0;
}

#texto-cor-hex {
    flex: 1;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: .03em;
    color: var(--texto);
}

/* biblioteca de imagens já geradas, dentro do modal "Adicionar imagem" */
/* Biblioteca do modal "Adicionar imagem": barra fixa (título + procura +
   grelha/lista) e só a lista rola. A procura e a paginação são do SERVIDOR
   (ver BibliotecaRepositorio) — o cliente nunca recebe a lista toda. */
#biblioteca {
    margin-top: 14px;
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

/* Enrola quando o modal é estreito (telemóvel): sem isto o título comia a
   linha e o campo de procura ficava com 0px de largura. */
.biblioteca-barra {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
}

.biblioteca-titulo {
    flex: 0 0 auto;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--texto-fraco);
}

.bib-procura {
    flex: 1 1 150px;
    min-width: 150px;
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 0 8px;
    background: var(--bg-sutil);
    border: 1px solid var(--borda);
    border-radius: 9px;
}

.bib-procura svg { flex: 0 0 auto; width: 14px; height: 14px; color: var(--texto-fraco); }

.bib-procura input {
    flex: 1 1 auto;
    min-width: 0;
    padding: 7px 0;
    font: inherit;
    font-size: 12px;
    color: var(--texto);
    background: transparent;
    border: 0;
    outline: none;
}

.bib-vistas {
    flex: 0 0 auto;
    display: flex;
    gap: 2px;
    padding: 2px;
    background: var(--bg-sutil);
    border-radius: 9px;
}

.bib-vistas button {
    width: 30px;
    height: 28px;
    display: grid;
    place-items: center;
    padding: 0;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: var(--texto-fraco);
    cursor: pointer;
}

.bib-vistas button svg { width: 15px; height: 15px; }

.bib-vistas button.ativa { background: var(--accent); color: var(--sobre-accent); }

#biblioteca-lista {
    flex: 1 1 auto;
    min-height: 120px;
    max-height: 260px;
    overflow-y: auto;
    overscroll-behavior: contain;
}

#biblioteca-grelha {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(78px, 1fr));
    gap: 8px;
}

.bib-item { position: relative; }

.bib-imagem {
    display: block;
    width: 100%;
    padding: 0;
    border: 2px solid var(--borda);
    border-radius: 10px;
    background: var(--bg-sutil-2);
    cursor: pointer;
    overflow: hidden;
    aspect-ratio: 1;
}

.bib-imagem:hover { border-color: var(--accent); }

#biblioteca-grelha img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* texto (pedido + data): só existe na vista de lista */
.bib-texto { display: none; }

.bib-pedido {
    font-size: 12px;
    color: var(--texto);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bib-data { font-size: 10.5px; color: var(--texto-fraco-2); }

/* × de remover: ao pairar no rato; sempre visível no toque, senão no
   telemóvel não havia forma nenhuma de tirar uma imagem da biblioteca. */
.bib-remover {
    position: absolute;
    top: 4px;
    right: 4px;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--fundo-sobreposto);
    color: #fff;
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
    display: none;
    align-items: center;
    justify-content: center;
}

.bib-item:hover .bib-remover { display: flex; }

.bib-remover:hover { background: var(--perigo-forte); }

@media (pointer: coarse) {
    .bib-remover { display: flex; }
}

/* vista de lista: miniatura pequena + pedido + data, uma por linha */
#biblioteca.vista-lista #biblioteca-grelha {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

#biblioteca.vista-lista .bib-item {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 4px;
    border-radius: 10px;
}

#biblioteca.vista-lista .bib-item:hover { background: var(--bg-sutil); }

#biblioteca.vista-lista .bib-imagem { flex: 0 0 auto; width: 46px; }

#biblioteca.vista-lista .bib-texto {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0;
}

#biblioteca.vista-lista .bib-remover { position: static; flex: 0 0 auto; display: flex; }

#bib-sentinela { height: 1px; }

.bib-carregar {
    padding: 10px 0;
    font-size: 11.5px;
    text-align: center;
    color: var(--texto-fraco-2);
}

/* lista de camadas (dentro do painel da direita) */
#lista-camadas {
    margin-top: 6px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-height: 52px;
}

.camadas-vazio {
    padding: 10px 6px;
    font-size: 11.5px;
    color: var(--texto-fraco);
    text-align: center;
}

/* Pastas da lista: "Geral" (imagens livres) + uma por molde. Também são alvo
   de largada — largar aqui muda a camada de pasta (fixa/solta do molde). */
.camada-pasta {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 8px;
    padding: 3px 6px;
    font-size: 11px;
    font-weight: 600;
    color: var(--texto-fraco);
    border-radius: 8px;
}

#lista-camadas .camada-pasta:first-child { margin-top: 0; }

.camada-pasta svg { width: 13px; height: 13px; flex: 0 0 auto; }

.camada-pasta .pasta-nome { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.camada-pasta .pasta-contagem { font-weight: 500; }

.camada-pasta.pasta-vazia { opacity: .55; }

.camada-pasta.solta-dentro { background: var(--accent-fraco-2); color: var(--accent); opacity: 1; }

/* arrastar para reordenar: a linha em trânsito esmorece; o risco marca onde cai */
.camada.arrastando { opacity: .35; }

.camada.solta-antes { box-shadow: 0 -2px 0 0 var(--accent); }

.camada.solta-depois { box-shadow: 0 2px 0 0 var(--accent); }

.camada {
    position: relative;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 5px 6px;
    border: 1px solid transparent;
    border-radius: 8px;
    cursor: pointer;
    user-select: none;
}

.camada:hover { background: var(--fundo-fraco); }

.camada.ativa {
    border-color: var(--accent);
    background: var(--accent-fraco-2);
}

.camada canvas {
    width: 38px;
    height: 30px;
    border: 1px solid var(--borda);
    border-radius: 5px;
    background:
        conic-gradient(var(--xadrez) 90deg, transparent 90deg 180deg, var(--xadrez) 180deg 270deg, transparent 270deg) 0 0 / 12px 12px;
    flex: 0 0 auto;
}

.camada .camada-nome {
    flex: 1;
    font-size: 12px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Estado (olho/cadeado/⋮) e ações partilham o canto direito, mas só o estado
   ocupa largura na linha: as ações abrem POR CIMA do nome (right: 100% em
   relação ao canto). Em fila, num painel de 260px, seis ícones de ação mais os
   de estado não cabem — o nome era espremido a 0 e os últimos botões saíam
   para fora do painel. */
.camada-ferramentas {
    position: relative;
    display: flex;
    flex: 0 0 auto;
}

.camada .camada-acoes {
    display: none;
    position: absolute;
    top: 50%;
    right: 100%;
    transform: translateY(-50%);
    gap: 2px;
    padding: 0 4px 0 8px;
    /* Fundo opaco (cor do painel) para tapar o nome por baixo em vez de o
       espremer. Os tons da linha (--fundo-fraco, --accent-fraco-2) são
       translúcidos — sozinhos deixavam o texto ver-se por entre os ícones —,
       por isso vão por cima como camada, tal como acontece na própria linha. */
    background-color: var(--bg-elevado);
}

.camada:hover .camada-acoes {
    background-image: linear-gradient(var(--fundo-fraco), var(--fundo-fraco));
}

.camada.ativa .camada-acoes {
    background-image: linear-gradient(var(--accent-fraco-2), var(--accent-fraco-2));
}

/* Sem rato não há hover que revele esta fila — aí quem manda é o ⋮ (ver o
   bloco do menu de camada mais abaixo). */
@media (hover: hover) and (pointer: fine) {
    .camada:hover .camada-acoes, .camada:focus-within .camada-acoes { display: flex; }
}

/* 18px e não 22px como os de estado: a linha mais cheia (texto fixo a um
   molde) leva seis destes e tem de caber entre a miniatura e o canto. */
.camada .camada-acoes button {
    width: 18px;
    height: 18px;
    border: 0;
    border-radius: 5px;
    background: transparent;
    color: var(--texto-fraco);
    font-size: 11px;
    line-height: 1;
    cursor: pointer;
    padding: 0;
}

/* mesmo realce dos botões de estado: o preto translúcido não se via no tema
   escuro, e agora que a fila é mais miudinha o alvo tem de se ler bem */
.camada .camada-acoes button:hover { background: var(--fundo-fraco-2); color: var(--texto); }

/* ------------------------------------------- painel de camadas (direita) */

/* Mesma anatomia do painel esquerdo: cartão fixo com overflow:hidden (para o
   botão de colapsar não abrir scroll) e um filho que é o único a rolar. */
#painel-camadas {
    position: fixed;
    top: 66px;
    right: var(--margem);
    bottom: var(--margem);
    width: var(--camadas-largura);
    z-index: 6;
    box-sizing: border-box;
    background: var(--bg-elevado);
    border: 1px solid var(--borda);
    border-radius: 14px;
    box-shadow: var(--sombra);
    color: var(--texto);
    /* ver a nota do #painel: a pega de colapsar não pode ser cortada */
    overflow: visible;
}

#painel-camadas-conteudo {
    height: 100%;
    min-width: 0;
    padding: 14px;
    box-sizing: border-box;
    overflow-y: auto;
    overflow-x: hidden;
}

/* clique em "Camadas" no rail (desktop): as camadas vivem neste painel — o
   pulso mostra ONDE, em vez de o clique parecer não fazer nada */
@keyframes pulso-camadas {
    0% { box-shadow: 0 0 0 0 var(--accent); }
    100% { box-shadow: 0 0 0 14px transparent; }
}

#painel-camadas.pulso-atencao { animation: pulso-camadas .55s ease-out 2; }

/* lista de partes — agora dentro do painel esquerdo (secção "Partes") */
#zonas {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.zona {
    position: relative;
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 10px 12px;
    box-sizing: border-box;
    border: 2px solid var(--borda);
    border-radius: 10px;
    background: var(--bg-elevado);
    cursor: pointer;
    font-family: inherit;
    color: inherit;
    text-align: left;
    transition: border-color .12s, box-shadow .12s;
}

.zona:hover {
    border-color: var(--borda-forte);
    box-shadow: var(--sombra-suave);
}

.zona.ativa {
    border-color: var(--accent);
    background: var(--accent-fraco-2);
    box-shadow: 0 0 0 1px var(--accent) inset;
}

/* check na peça ativa, como nos configuradores comerciais — para dentro do
   cartão (não transborda) porque a lista agora é vertical, com pouco espaço
   entre cartões consecutivos. */
.zona.ativa::after {
    content: '✓';
    position: absolute;
    top: 8px;
    right: 8px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--accent);
    color: var(--sobre-accent);
    font-size: 10px;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
}

.zona .amostra {
    width: 40px;
    height: 40px;
    flex: 0 0 auto;
    /* a sombra segue a forma do molde — sem ela, um molde branco sumia no card */
    filter: drop-shadow(0 0 1px var(--halo-amostra));
}

.zona-textos {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.zona .etiqueta {
    font-size: 13px;
    font-weight: 700;
    color: var(--texto);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.zona-desc {
    font-size: 11px;
    color: var(--texto-fraco);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* --------------------------------------------------- miniatura 3D e modal */

#mini3d {
    position: fixed;
    display: flex;
    flex-direction: column;
    left: calc(var(--painel-largura) + var(--margem) * 2 + 14px);
    bottom: calc(var(--margem) + 14px);
    width: 320px;
    height: 360px;
    background: var(--palco-bg);
    border: 1px solid var(--borda);
    border-radius: 12px;
    box-shadow: var(--sombra);
    overflow: hidden;
    z-index: 7;
}

/* corpo da janela flutuante: o que sobra depois do cabeçalho */
#palco { flex: 1 1 auto; min-height: 0; width: 100%; }

/* Sem isto, um arrasto no ecrã tátil é disputado entre o OrbitControls e o
   scroll/pan nativo do browser: o gesto pode ser cancelado a meio e a rotação
   sai errática/invertida (o dedo continua a mexer mas o evento já não chega
   ao three.js). O canvas é sempre o mesmo re-parentado (moverPalcoPara). */
#palco canvas, #palco-grande canvas, #palco-principal-caixa canvas {
    display: block;
    touch-action: none;
}

/* Alça para encolher/aumentar o cartão do 3D (pedido do utilizador: o cartão
   por vezes tapa peças do 2D por baixo — ver painel.js/redimensionarMini3d). */
#mini3d-redimensionar {
    position: absolute;
    right: 2px;
    bottom: 2px;
    width: 18px;
    height: 18px;
    cursor: nwse-resize;
    touch-action: none;
    z-index: 2;
}

#mini3d-redimensionar::after {
    content: '';
    position: absolute;
    right: 4px;
    bottom: 4px;
    width: 9px;
    height: 9px;
    border-right: 2px solid var(--borda-forte);
    border-bottom: 2px solid var(--borda-forte);
    border-radius: 0 0 2px 0;
}

#mini3d-redimensionar:hover::after { border-color: var(--texto-fraco); }

#modal-3d {
    position: fixed;
    inset: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--scrim);
}

.caixa-3d {
    position: relative;
    width: min(86vmin, 900px);
    height: min(86vmin, 900px);
    background: var(--palco-bg);
    border-radius: 14px;
    box-shadow: var(--sombra-modal);
    overflow: hidden;
}

#palco-grande { width: 100%; height: 100%; }

#bt-fechar-3d {
    position: absolute;
    right: 10px;
    top: 10px;
    z-index: 2;
    width: 32px;
    height: 32px;
    border: 1px solid var(--borda);
    border-radius: 9px;
    background: var(--bg-elevado);
    font-size: 17px;
    line-height: 1;
    cursor: pointer;
}

#bt-fechar-3d:hover { background: var(--bg-sutil); border-color: var(--borda-forte); }

/* ---------------------------------------------------------- modal da IA */

#modal-ia {
    position: fixed;
    inset: 0;
    z-index: 32;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--scrim);
}

.caixa-ia {
    position: relative;
    width: min(92vw, 380px);
    padding: 18px 18px 16px;
    background: var(--bg-elevado);
    border-radius: 14px;
    box-shadow: var(--sombra-modal);
    box-sizing: border-box;
}

/* O modal de adicionar é o único que leva a biblioteca dentro: mais largo e
   com teto de altura, para a lista rolar por dentro em vez de esticar o
   modal para fora do ecrã. */
.caixa-adicionar {
    width: min(94vw, 560px);
    max-height: 88vh;
    display: flex;
    flex-direction: column;
}

.ia-titulo { margin: 0 24px 10px 0; font-size: 15px; }

#bt-fechar-ia,
.bt-fechar-modal {
    position: absolute;
    top: 10px;
    right: 10px;
    width: 28px;
    height: 28px;
    font-size: 17px;
    line-height: 1;
    color: var(--texto);
    background: var(--fundo-fraco);
    border: 1px solid var(--borda);
    border-radius: 8px;
    cursor: pointer;
}

#bt-fechar-ia:hover,
.bt-fechar-modal:hover { background: var(--fundo-fraco-2); }

.ia-explica { margin: 0 0 10px; font-size: 12.5px; line-height: 1.45; color: var(--texto-fraco-2); }

.ia-rotulo { display: block; margin: 10px 0 4px; font-size: 12px; font-weight: 600; }

.ia-nota { font-size: 11px; font-weight: 400; color: var(--texto-fraco-2); }

p.ia-nota { margin: 8px 0 0; }

#modal-ia input[type="password"],
#ia-pedido {
    width: 100%;
    padding: 8px 10px;
    font: inherit;
    font-size: 12.5px;
    border: 1px solid var(--borda-campo);
    border-radius: 8px;
    box-sizing: border-box;
    outline: none;
}

#modal-ia input[type="password"]:focus,
#ia-pedido:focus { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(108, 92, 231, .15); }

#ia-pedido { resize: vertical; min-height: 64px; }

/* conversa de refinamento (histórico de gerações dentro do modal) */
#ia-chat {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-height: 220px;
    overflow-y: auto;
    margin-bottom: 10px;
    padding-right: 2px;
}

.ia-msg {
    max-width: 86%;
    padding: 7px 10px;
    border-radius: 11px;
    font-size: 12.5px;
    line-height: 1.4;
}

.ia-msg.user {
    align-self: flex-end;
    background: var(--accent);
    color: var(--sobre-accent);
    border-bottom-right-radius: 4px;
}

.ia-msg.ia {
    align-self: flex-start;
    background: var(--bg-sutil-2);
    color: var(--texto);
    border-bottom-left-radius: 4px;
}

/* Tira do resultado: os quatro lados do 3D + o mapa 2D, lado a lado. */
.ia-msg-imagens {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: 6px;
}

.ia-msg img {
    display: block;
    width: 62px;
    height: 62px;
    /* contain e não cover: vale mais ver a peça inteira pequena do que um
       pedaço grande dela */
    object-fit: contain;
    /* o palco é claro nos dois temas — as fotos vêm com este fundo */
    background: var(--palco-bg);
    border-radius: 8px;
    border: 1px solid var(--borda);
    cursor: zoom-in;
}

.ia-msg img:hover { border-color: var(--accent); }

/* Ações da última resposta: o design já está aplicado no editor, portanto
   "aceitar" é só fechar o modal e voltar ao trabalho. */
.ia-msg-acoes {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
}

.ia-msg-acoes button {
    padding: 6px 10px;
    font: inherit;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--texto);
    background: var(--bg-elevado);
    border: 1px solid var(--borda);
    border-radius: 999px;
    cursor: pointer;
}

.ia-msg-acoes button:hover { border-color: var(--accent); }

.ia-msg-acoes button.principal {
    color: var(--sobre-accent);
    background: var(--accent);
    border-color: var(--accent);
}

/* imagem gerada em grande, por cima do próprio modal da IA */
#lightbox-ia {
    position: fixed;
    inset: 0;
    z-index: 40;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: var(--scrim);
}

#lightbox-ia img {
    /* "Ecrã inteiro" a sério: estica a imagem até quase encher o ecrã mesmo
       quando o ficheiro é pequeno (as fotos dos lados vêm reduzidas) — antes
       abria no tamanho natural e ficava um selo no meio do escuro. */
    height: min(88vh, 88vw);
    width: auto;
    max-width: 94vw;
    object-fit: contain;
    background: var(--palco-bg);
    border-radius: 12px;
    box-shadow: var(--sombra-modal);
}

#bt-fechar-lightbox {
    position: absolute;
    top: 14px;
    right: 14px;
    width: 34px;
    height: 34px;
    font-size: 20px;
    line-height: 1;
    color: var(--texto);
    background: var(--bg-elevado);
    border: 1px solid var(--borda);
    border-radius: 50%;
    cursor: pointer;
}

#ia-modo {
    display: flex;
    gap: 6px;
    margin-top: 8px;
}

.ia-chip {
    flex: 1;
    padding: 7px 8px;
    font: inherit;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--texto);
    background: var(--bg-sutil);
    border: 1px solid var(--borda);
    border-radius: 999px;
    cursor: pointer;
    /* Uma etiqueta mais longa (esp. noutras línguas) não pode quebrar para
       2 linhas — isso desalinhava a altura desta pill com as outras duas
       do mesmo grupo. O título (tooltip) leva a explicação completa. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* o par de modos divide a linha; a qualidade é um extra e fica só com o
   tamanho do texto */
.ia-chip-qualidade { flex: 0 0 auto; }

.ia-chip.ativa {
    color: var(--accent);
    border-color: var(--accent);
    background: var(--accent-fraco-2);
}

/* Antes era um link de texto sozinho no meio de pills sólidas (chips do modo,
   botão "Gerar design") — destoava do resto do modal. Agora é uma pill
   fantasma da mesma família, com o traço tracejado a sugerir "anexo". */
.ia-anexo {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 10px;
    padding: 7px 10px;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    color: var(--accent);
    background: var(--bg-sutil);
    border: 1px dashed var(--borda);
    border-radius: 999px;
    cursor: pointer;
    text-align: left;
}

.ia-anexo:hover { background: var(--accent-fraco-2); border-color: var(--accent); }

#ia-referencia-preview {
    position: relative;
    display: inline-block;
    margin-top: 8px;
}

#ia-referencia-img {
    max-width: 120px;
    max-height: 90px;
    border-radius: 8px;
    border: 1px solid var(--borda);
    display: block;
}

#bt-tirar-referencia {
    position: absolute;
    top: -7px;
    right: -7px;
    width: 20px;
    height: 20px;
    font-size: 12px;
    line-height: 1;
    color: var(--texto-contraste);
    background: var(--bg-contraste);
    border: 0;
    border-radius: 50%;
    cursor: pointer;
}

#ia-progresso {
    display: flex;
    flex-direction: column;
    gap: 9px;
    padding: 18px 0 10px;
}

#ia-progresso-texto { font-size: 13px; color: var(--texto); line-height: 1.45; }

.ia-prog-cabeca {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
}

.ia-prog-tempo {
    flex: none;
    font-size: 11.5px;
    color: var(--texto-fraco-2);
    font-variant-numeric: tabular-nums;
}

.ia-prog-barra {
    height: 8px;
    border-radius: 99px;
    background: var(--fundo-fraco-2);
    overflow: hidden;
}

#ia-prog-fita {
    position: relative;
    width: 0;
    height: 100%;
    border-radius: 99px;
    background: linear-gradient(90deg, var(--accent), var(--accent-hover));
    transition: width .45s ease-out;
}

/* Brilho a atravessar a fita: garante movimento mesmo quando o valor estagna
   à espera da resposta da OpenAI. */
#ia-prog-fita::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 99px;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .4), transparent);
    animation: iaBrilho 1.5s linear infinite;
}

@keyframes iaBrilho {
    from { transform: translateX(-100%); }
    to   { transform: translateX(100%); }
}

.ia-prog-dica {
    margin: 2px 0 0;
    min-height: 2.6em;
    font-size: 12px;
    line-height: 1.45;
    color: var(--texto-fraco-2);
    opacity: 1;
    transition: opacity .2s ease;
}

.ia-prog-dica.a-sair { opacity: 0; }

.ia-prog-aviso {
    margin: 0;
    font-size: 11.5px;
    line-height: 1.4;
    color: var(--texto-fraco);
}

/* Clicar fora ou carregar em Escape a meio da geração não fecha nada — em vez
   de parecer que a janela ignorou o clique, o aviso pisca. */
.ia-prog-aviso.pisca { animation: iaAvisoPisca 1s ease; }

@keyframes iaAvisoPisca {
    0%, 100% { color: var(--texto-fraco); transform: none; }
    15%      { color: var(--accent-texto); transform: translateX(-3px); }
    45%      { color: var(--accent-texto); transform: translateX(3px); }
    70%      { color: var(--accent-texto); transform: none; }
}

/* Depois do :hover lá em cima, senão o botão desativado ainda acendia ao rato. */
#bt-fechar-ia:disabled,
#bt-fechar-ia:disabled:hover {
    opacity: .35;
    cursor: not-allowed;
    background: var(--fundo-fraco);
}

@media (prefers-reduced-motion: reduce) {
    #ia-prog-fita::after { animation: none; }
    .ia-prog-aviso.pisca { animation: none; color: var(--accent-texto); }
}

/* ─────────────────── chat da IA ancorado à direita (PC largo) ───────────────
   Modal centrado tapa exatamente o que se está a pedir para mudar. Em ecrã
   largo o mesmo #modal-ia deixa de ser overlay e passa a ser uma COLUNA à
   esquerda do painel de camadas — o modelo fica à vista e vê-se o design a
   entrar enquanto se conversa. Mesmo DOM, mesmo JS: só muda o sítio.

   Porquê 1400px e não 901px: à esquerda são 336px e à direita 260px de
   painéis; com mais 340px de chat, abaixo dos ~1400 o palco ficaria com menos
   de 420px e o modelo passava a caber pior do que com o modal por cima. Nos
   ecrãs mais estreitos (e no telemóvel) continua modal — que é o que a
   decisão de 2026-07-27 previa. O corpo leva .ia-ancorada sempre que o modal
   está aberto; fora deste breakpoint a classe não faz nada. */
@media (min-width: 1400px) {
    /* --ia-faixa é o que o palco perde à direita (coluna + folga). Vale 0px
       fora daqui, por isso os calc() do palco não precisam de variante. */
    body.ia-ancorada { --ia-faixa: calc(var(--ia-largura) + var(--margem)); }

    body.ia-ancorada #modal-ia {
        top: 66px;
        bottom: var(--margem);
        left: auto;
        right: calc(var(--camadas-largura) + var(--margem) * 2);
        width: var(--ia-largura);
        display: block;
        /* sem scrim: o resto da aplicação continua a usar-se com o chat aberto */
        background: none;
    }

    /* A caixa passa a preencher a coluna: cabeçalho e composer fixos, e só a
       conversa é que rola (anatomia dos painéis laterais). */
    body.ia-ancorada #modal-ia .caixa-ia {
        width: 100%;
        height: 100%;
        display: flex;
        flex-direction: column;
        border: 1px solid var(--borda);
        box-shadow: var(--sombra);
        overflow: hidden;
    }

    body.ia-ancorada #ia-passo-pedido,
    body.ia-ancorada #ia-passo-chaves {
        display: flex;
        flex-direction: column;
        min-height: 0;
        flex: 1;
    }

    body.ia-ancorada #ia-passo-pedido.escondido,
    body.ia-ancorada #ia-passo-chaves.escondido { display: none; }

    /* o histórico é o único que estica e rola */
    body.ia-ancorada #ia-chat {
        flex: 1;
        min-height: 0;
        max-height: none;
    }

    /* Sem conversa ainda, o composer ficava colado ao título com a coluna
       toda vazia por baixo — empurra-se para o fundo, como num chat a sério. */
    body.ia-ancorada #ia-chat.escondido + #ia-pedido { margin-top: auto; }

    /* numa coluna alta as miniaturas do resultado podem respirar */
    body.ia-ancorada .ia-msg { max-width: 92%; }
    body.ia-ancorada .ia-msg img { width: 72px; height: 72px; }
}

#ia-erro {
    margin-top: 10px;
    padding: 8px 10px;
    font-size: 12.5px;
    line-height: 1.4;
    color: var(--perigo);
    background: var(--perigo-fraco);
    border-radius: 8px;
}

/* menu de contexto (botão direito): partilhado pelo 3D e pelo editor 2D */
.menu-contexto {
    position: fixed;
    z-index: 44;
    min-width: 150px;
    padding: 6px;
    background: var(--bg-elevado);
    border: 1px solid var(--borda);
    border-radius: 10px;
    box-shadow: var(--sombra-menu);
}

.menu-zona-nome {
    padding: 5px 8px 7px;
    font-size: 12px;
    font-weight: 700;
    color: var(--texto);
    border-bottom: 1px solid var(--borda);
    margin-bottom: 5px;
}

.menu-contexto button {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 7px 8px;
    font: inherit;
    font-size: 12px;
    text-align: left;
    color: var(--texto);
    background: transparent;
    border: 0;
    border-radius: 7px;
    cursor: pointer;
}

.menu-contexto button:hover { background: var(--bg-sutil); }
.menu-contexto button.perigo { color: var(--perigo); }
.menu-contexto button:disabled { color: var(--texto-fraco-2); cursor: default; }
.menu-contexto button:disabled:hover { background: transparent; }

/* Secções dentro do menu de estouro (⋮): idioma e tema deixaram de ter botão
   próprio na barra de topo e vivem aqui. O título é rótulo, não é clicável —
   daí o cursor e a cor fracos, para não se confundir com uma opção. */
.menu-titulo {
    padding: 7px 8px 3px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--texto-fraco-2);
}

/* O interruptor de tema é um botão de 32px vindo de includes/tema_botao.php:
   não tem rótulo próprio, por isso a linha empresta-lhe um. */
.menu-linha {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 8px 6px;
}

.menu-linha-rotulo { font-size: 12px; color: var(--texto); }

/* O hover de omissão do botão usa --surface-2, que aqui não existe e cai em
   --bg-elevado — a mesma cor do menu, ou seja, hover invisível. */
.menu-linha #tema-botao:hover { background: var(--bg-sutil); }

.menu-separador {
    height: 1px;
    margin: 6px 4px;
    background: var(--borda);
}

/* Bandeiras em linha e não empilhadas: quatro idiomas de pé fariam o menu
   crescer meio ecrã no telemóvel. */
.menu-idiomas {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding: 2px 6px 4px;
}

.menu-idioma {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 9px;
    font-size: 12px;
    font-weight: 600;
    color: var(--texto-fraco);
    text-decoration: none;
    border: 1px solid transparent;
    border-radius: 8px;
}

.menu-idioma img { width: 16px; height: 12px; object-fit: cover; border-radius: 2px; flex: none; }

.menu-idioma:hover { background: var(--bg-sutil); color: var(--texto); }

.menu-idioma.ativa {
    color: var(--texto);
    background: var(--bg-sutil);
    border-color: var(--borda);
}

/* ----------------------------------------------------------------- overlay */

.overlay {
    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 14px;
    background: var(--overlay-fundo);
    z-index: 40;
}

.overlay.escondido { display: none; }

.spinner {
    width: 34px;
    height: 34px;
    border: 3px solid var(--borda);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: rodar .8s linear infinite;
}

@keyframes rodar { to { transform: rotate(360deg); } }

.overlay-texto { font-size: 13px; color: var(--texto-fraco); }

/* marca no loading (chamados #120/#124) — mesmas cores do .brand do topo */
.overlay-marca { font-size: 26px; font-weight: 800; letter-spacing: -.02em; }

.overlay-marca .overlay-marca-sufixo { color: var(--texto-fraco); font-weight: 600; }

.overlay-erro {
    display: none;
    max-width: 380px;
    text-align: center;
    font-size: 13px;
    line-height: 1.5;
    color: var(--perigo);
}

/* Telemóvel: cada bloco tem a sua faixa — nada flutua por cima do canvas.
   Topo: cabeçalho + miniatura 3D · ferramentas na horizontal · canvas ·
   folha "Editar" (30vh, painel + rail de secções) · tira de peças. */

/* ------------------------------------- lados do modelo (presets de câmara) */

/* Mesma faixa do alternador 3D/2D, logo por baixo dele. Só aparece na vista
   3D — em 2D não há câmara para rodar (ver aplicarVista em painel.js). */
#vistas-camara {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 4px;
    pointer-events: none;
}

.vista-btn {
    pointer-events: auto;
    font: inherit;
    font-size: 11.5px;
    font-weight: 600;
    padding: 6px 12px;
    border: 1px solid var(--borda);
    border-radius: 999px;
    background: var(--bg-elevado);
    color: var(--texto-fraco);
    box-shadow: var(--sombra);
    cursor: pointer;
    white-space: nowrap;
}

.vista-btn:hover { color: var(--texto); border-color: var(--borda-forte); }

.vista-btn.ativa {
    color: var(--sobre-accent);
    background: var(--accent);
    border-color: var(--accent);
}

/* --------------------------------------------- cores recentes de uma peça */

#cores-recentes {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.cor-recente {
    width: 26px;
    height: 26px;
    padding: 0;
    border: 1px solid var(--borda-campo);
    border-radius: 8px;
    cursor: pointer;
    /* xadrez por baixo: uma cor quase igual ao painel deixaria de se ver */
    background-image: linear-gradient(var(--cor-amostra), var(--cor-amostra)),
        conic-gradient(var(--xadrez) 90deg, transparent 90deg 180deg, var(--xadrez) 180deg 270deg, transparent 270deg);
    background-size: 100% 100%, 10px 10px;
}

.cor-recente:hover { border-color: var(--borda-forte); transform: scale(1.08); }

/* ------------------------------------ abas do painel de camadas (direita) */

/* A linha das abas leva o "+" (adicionar imagem) à direita: o botão largo que
   ocupava uma linha só para si comia altura da folha no telemóvel. */
.painel-abas-linha {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 10px 0 8px;
}

.painel-abas {
    display: flex;
    flex: 1;
    min-width: 0;
    gap: 2px;
    padding: 3px;
    border-radius: 10px;
    background: var(--bg-sutil);
}

/* align-self: stretch em vez de altura fixa — assim tem exatamente a altura
   da tira das abas ao lado, em vez de ficar 2px mais alto que ela. */
.aba-acao {
    flex: 0 0 auto;
    align-self: stretch;
    display: grid;
    place-items: center;
    width: 36px;
    min-height: 32px;
    padding: 0;
    color: var(--sobre-accent);
    background: var(--accent);
    border: 1px solid var(--accent);
    border-radius: 10px;
    cursor: pointer;
}

.aba-acao:hover { background: var(--accent-hover); }

/* variante discreta (botão do texto): o "+" continua a ser a ação primária */
.aba-acao.secundaria {
    color: var(--accent-texto);
    background: transparent;
    border-color: var(--borda-campo);
}

.aba-acao.secundaria:hover { background: var(--fundo-fraco); }

.aba-acao svg { width: 18px; height: 18px; }

.painel-aba {
    flex: 1;
    /* sem isto o min-width:auto dos flex items impede a aba de encolher
       abaixo da largura de "Propriedades" — em ecrã estreito o texto passava
       por baixo dos botões T/+ ao lado; com teto encolhe com reticências */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding: 6px 8px;
    font: inherit;
    font-size: 11.5px;
    font-weight: 600;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: var(--texto-fraco);
    cursor: pointer;
}

.painel-aba:hover { color: var(--texto); }

.painel-aba.ativa {
    color: var(--sobre-accent);
    background: var(--accent);
}

.aba-conteudo { display: none; }

.aba-conteudo.ativa { display: block; }

/* ------------------------------- estado de cada camada (ver/esconder, bloquear) */

/* Ao contrário de .camada-acoes (que só aparece no hover), estes dois estão
   sempre visíveis: são estado da camada, não ações escondidas. */
.camada-estado {
    display: flex;
    gap: 2px;
    flex-shrink: 0;
}

.camada-estado button {
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: var(--texto-fraco);
    cursor: pointer;
}

.camada-estado button:hover { background: var(--fundo-fraco-2); color: var(--texto); }

.camada-estado svg { width: 14px; height: 14px; fill: currentColor; }

/* escondida: fica esbatida mas legível — ainda é preciso saber o que é para
   a voltar a ligar */
.camada.camada-oculta .camada-nome,
.camada.camada-oculta canvas { opacity: .4; }

.camada.camada-oculta .camada-olho { color: var(--accent); }

.camada.camada-bloqueada .camada-cadeado { color: var(--accent); }

/* bloqueada não se arrasta no palco: o cursor tem de dizer isso já na lista */
.camada.camada-bloqueada { cursor: default; }

/* -------------------------------------------- recolher a folha (telemóvel) */

/* Pastilha na borda de cima da folha: recolhe-a para o palco ficar inteiro,
   sem obrigar a trocar de secção. Fica sempre no limite superior da folha,
   por isso acompanha a altura dela — encostada à direita, porque a barra de
   ferramentas ocupa agora o canto esquerdo dessa mesma borda.
   Declarado ANTES das media queries de propósito: com a mesma especificidade,
   ganha quem vem depois, e as regras de telemóvel/paisagem precisam de poder
   mudar estes valores. */
#bt-recolher-folha {
    position: fixed;
    right: 8px;
    bottom: calc(var(--m-nav-h) + var(--m-painel-h) + 4px);
    z-index: 8;
    width: 52px;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid var(--borda);
    border-radius: 999px;
    background: var(--bg-elevado);
    color: var(--texto-fraco);
    box-shadow: var(--sombra);
    cursor: pointer;
}

#bt-recolher-folha svg { width: 16px; height: 16px; transition: transform .15s; }

body.folha-recolhida #bt-recolher-folha svg { transform: rotate(180deg); }

@media (max-width: 900px) {

    /* Em 3D a miniatura está escondida, por isso a faixa do topo está livre
       para os lados do modelo — é no telemóvel que arrastar para rodar é
       mais incómodo, portanto os presets fazem aqui ainda mais falta. */
    #vistas-camara { gap: 3px; }

    .vista-btn { font-size: 10.5px; padding: 5px 9px; }

    .painel-abas-linha { margin: 8px 0 6px; }

    /* alvo de toque: a altura do + vem das abas, por isso são elas que crescem
       — e ganham também um alvo decente (antes 26px de altura útil). */
    .aba-acao { width: 42px; }

    .painel-aba { padding: 11px 8px; }

    /* colapsar só faz sentido na faixa central larga do desktop — no
       telemóvel painel/partes já são faixas empilhadas de largura fixa. */
    .bt-colapsar { display: none; }

    #topo { padding: 0 10px; height: 48px; }

    .brand { font-size: 15px; }

    /* #104: no telemóvel o cabeçalho não tinha espaço para a etiqueta +
       seletor + botões com texto — "Guardar"/"Exportar" saíam do ecrã e
       criavam scroll horizontal na página toda. Etiqueta escondida, botões
       só com ícone (o title continua a servir de rótulo acessível) e o
       seletor de modelo com largura travada. */
    .marca .badge { display: none; }

    /* "Os meus designs" quebrava em três linhas e passava por cima do pWdev —
       o botão de voltar fica só com a seta (o title continua a ser o rótulo
       acessível), como manda a norma para a barra de topo em ecrã estreito. */
    .topo-voltar-rotulo { display: none; }

    .topo-voltar { padding: 7px; }

    .topo-centro { position: static; transform: none; }

    #sel-modelo { padding: 6px 8px; font-size: 12px; max-width: 92px; text-overflow: ellipsis; }

    .topo-acoes { gap: 6px; }

    .topo-botao { padding: 7px; }

    .topo-botao-rotulo { display: none; }

    .topo-botao .ico { margin: 0; }

    /* Espaço reservado no fundo: uma folha só de cada vez (ou o painel
       esquerdo, ou o de camadas — ver aplicarSecaoMobile em painel.js), com
       altura dependente da secção ativa. "Partes" fica numa tira baixa
       (pílulas horizontais com scroll lateral, sem título) porque escolher a
       peça é um gesto rápido e o palco é que interessa; as outras secções
       precisam da folha inteira. */
    :root {
        --m-nav-h: 54px;
        --m-painel-h: 30vh;
    }
    /* --m-painel-h deixa de ser um número fixo: é medido em painel.js a partir
       da folha visível (ver atualizarAlturaFolha). Com 30vh fixos, "Texturas"
       — uma linha de padrões — deixava metade da folha vazia e o palco pagava
       por isso. Este valor é só o ponto de partida antes da 1.ª medição. */
    body { --m-painel-h: 30vh; }
    body[data-secao-mobile="partes"] { --m-painel-h: 104px; }
    body.folha-recolhida { --m-painel-h: 0px; }
    body.folha-recolhida #painel,
    body.folha-recolhida #painel-camadas { display: none; }

    #barra-vistas { top: 54px; left: 8px; right: 8px; padding-top: 8px; gap: 6px; }

    .alt-btn { padding: 5px 13px; font-size: 11.5px; }

    #mini3d {
        left: auto;
        bottom: auto;
        top: 56px;
        right: 8px;
        width: 96px;
        height: 112px;
    }

            /* Selecionar/Mover/Mão saem do mobile — o ecrã tátil já usa sempre o modo
       "auto" (seleciona e arrasta a vista sozinho), trocar de ferramenta não
       traz nada; só sobra zoom/enquadrar/desfazer/refazer. */
    #fer-selecionar,
    #fer-auto,
    #fer-mao,
    .editor-ferramentas .fer-divisor:first-of-type {
        display: none;
    }

    /* No telemóvel volta a ser horizontal, mas encostada ao canto INFERIOR
       esquerdo do palco: a meio do ecrã (era top:178px) ficava mesmo por
       cima dos moldes, e em baixo fica na zona do polegar. A pastilha de
       recolher a folha vai para o canto oposto — uma em cada ponta da borda
       de baixo, sem nada empilhado sobre o desenho. */
    .editor-ferramentas {
        flex-direction: row;
        top: auto;
        bottom: calc(var(--m-nav-h) + var(--m-painel-h) + 16px);
        left: 8px;
        right: auto;
        transform: none;
        width: max-content;
        max-width: calc(100% - 16px);
        justify-content: center;
        border-radius: 999px;
        padding: 4px;
        gap: 2px;
    }

    .ferramenta { width: 32px; height: 32px; flex: 0 0 auto; }

    .ferramenta svg { width: 17px; height: 17px; }

    .fer-divisor { width: 1px; height: 20px; margin: 0 2px; }

    /* top mínimo — só a folga do cabeçalho. Alternador/miniatura/ferramentas
       são overlays a sério (mesma lógica do desktop), não reservam faixa. */
    #editor-principal,
    #palco-principal {
        top: 58px;
        left: 8px;
        right: 8px;
        bottom: calc(var(--m-nav-h) + var(--m-painel-h) + 8px);
    }

    #controlos-3d { width: min(280px, 90%); bottom: 10px; }

    /* folha "Editar": painel (só o conteúdo agora, o rail saiu daqui — ver
       #nav-secoes abaixo) ocupa a faixa logo acima da barra de abas. O painel
       de camadas usa exatamente a mesma faixa — no telemóvel não há "lado",
       só a folha da secção ativa. */
    #painel,
    #painel-camadas {
        top: auto;
        left: 8px;
        right: 8px;
        bottom: var(--m-nav-h);
        width: auto;
        /* altura do conteúdo, com teto — nunca a folha comer o palco todo */
        height: auto;
        max-height: 44vh;
    }

    /* Os conteúdos rolam por overflow-y:auto com height:100% — mas aqui o
       pai passou a height:auto e a percentagem deixa de resolver: o filho
       crescia ao tamanho do conteúdo e as Propriedades ficavam cortadas sem
       scroll (chamado #108, "opções avançadas não ficam visíveis"). O teto
       tem de viver também no filho que rola. */
    #painel-conteudo,
    #painel-camadas-conteudo {
        max-height: 44vh;
    }

    /* só a secção clicada aparece de cada vez (liberta espaço em vez de
       empilhar tudo) — ver painel.js: aplicarSecaoMobile() alterna estas
       classes conforme o separador tocado. */
    #painel.secao-fechada-mobile,
    #painel-camadas.secao-fechada-mobile {
        display: none;
    }

    #painel-conteudo [data-secao] { display: none; }
    #painel-conteudo [data-secao].secao-ativa-mobile { display: block; }
    #painel-peca.secao-fechada-mobile { display: none; }

    /* rail de secções vira barra de abas fixa no fundo do ecrã (era uma
       coluna vertical espremida dentro do painel — o utilizador reparou que
       ficava errado; no mobile faz mais sentido como bottom-nav a sério). */
    #nav-secoes {
        position: fixed;
        top: auto;
        left: 0;
        right: 0;
        bottom: 0;
        width: auto;
        height: var(--m-nav-h);
        flex-direction: row;
        justify-content: space-around;
        align-items: center;
        padding: 4px;
        border-right: 0;
        border-radius: 0;
        border-top: 1px solid var(--borda);
        box-shadow: none;
        z-index: 20;
    }

    #nav-secoes button { padding: 4px 2px; }

    #nav-secoes button span { font-size: 8.5px; }

    #painel-conteudo { padding: 10px 12px; }

    .painel-titulo { font-size: 13px; }

    .painel-titulo.seccao { margin-top: 10px; padding-top: 8px; }

    .botao-largo { margin-top: 6px; padding: 8px 10px; }

        /* padrões de estampa: uma linha só, scroll horizontal — o grid de 4
       colunas obrigava a rolar a folha inteira de 30vh na vertical só para
       ver os últimos padrões. */
    #estampas, #tecidos {
        display: flex;
        overflow-x: auto;
        gap: 6px;
        padding-bottom: 4px;
    }

    .estampa { flex: 0 0 76px; }

    /* tira de peças: a secção "Partes" dentro da folha vira uma faixa
       horizontal com scroll — mesmos elementos (#zonas/.zona), só
       reorientados por CSS. Sem título: numa tira de 104px cada linha conta. */
    #painel-conteudo [data-secao="partes"] .painel-titulo { display: none; }

    #painel-camadas-conteudo { padding: 10px 12px; }

    #zonas {
        flex-direction: row;
        overflow-x: auto;
        overflow-y: hidden;
        width: 100%;
        justify-content: flex-start;
    }

    .zona {
        flex-direction: column;
        align-items: center;
        justify-content: center;
        text-align: center;
        width: auto;
        min-width: 62px;
        padding: 7px 8px 6px;
        gap: 5px;
    }

    .zona .amostra { width: 26px; height: 26px; }

    .zona-textos { align-items: center; }

    .zona .etiqueta {
        font-size: 9px;
        max-width: 72px;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* sem espaço numa pílula pequena — a descrição só existe na lista do desktop */
    .zona-desc { display: none; }


    .caixa-3d { width: min(94vw, 94vh); height: min(94vw, 94vh); }
}

/* Desktop: o rail filtra o painel esquerdo tal como no telemóvel — só a
   secção escolhida aparece (antes empilhava-se tudo e o rail era um mero
   scroll: clicar em "Partes" mostrava também cor, estampa e tecido).
   Ver painel.js: aplicarSecaoDesktop() alterna estas classes. */
@media (min-width: 901px) {
    #painel-conteudo .secao-painel:not(.secao-ativa-desktop) { display: none; }
    #painel-peca.secao-fechada-desktop { display: none; }
    /* a dica de "nada selecionado" pertence às secções de contexto */
    body:not([data-secao-desktop="cores"]):not([data-secao-desktop="texturas"]) #painel-conteudo > #painel-dica { display: none; }
}

/* O viewport trava o zoom manual (user-scalable=no no index.php — sem isto o
   pinch nativo do browser brigava com o pan/zoom próprios do editor e do 3D).
   Só que o Safari do iOS IGNORA user-scalable/maximum-scale desde o iOS 10: o
   que ele respeita é o tamanho da letra do campo focado — abaixo de 16px dá
   zoom na marra e desalinha a página inteira, e não desfaz o zoom ao sair do
   campo.

   Regra por TIPO de campo, não por id: a versão anterior listava ids um a um
   e ficou desatualizada assim que apareceram campos novos (os de Propriedades
   entraram a 12,5px). Por ecrã tátil e não por largura, porque um iPad em
   paisagem passa dos 900px e tem o mesmo comportamento.

   O !important é preciso: as regras base usam ids (#sel-modelo, #sel-idioma),
   que ganham sempre a um seletor de tipo. A alternativa era voltar a
   enumerá-los — que é exatamente o que apodreceu. */
@media (pointer: coarse) {
    select,
    textarea,
    input:not([type]),
    input[type="text"],
    input[type="number"],
    input[type="password"],
    input[type="search"],
    input[type="email"],
    input[type="tel"],
    input[type="url"] {
        font-size: 16px !important;
    }
}

/* --------------------------------- fechar/repor a pré-visualização 3D (2D) */

/* A miniatura tapa peças do molde em ecrãs baixos e nem sempre é precisa —
   daí poder fechar-se. Fechar não pode ser porta sem retorno: a pastilha
   #bt-repor-mini3d ocupa o mesmo canto e traz o 3D de volta. As duas só
   existem no modo 2D (em 3D o palco JÁ é o modelo). */
#bt-repor-mini3d {
    position: fixed;
    left: calc(var(--painel-largura) + var(--margem) * 2 + 14px);
    bottom: calc(var(--margem) + 14px);
    z-index: 7;
    padding: 7px 14px;
    font: inherit;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .04em;
    border: 1px solid var(--borda);
    border-radius: 999px;
    background: var(--bg-elevado);
    color: var(--texto);
    box-shadow: var(--sombra);
    cursor: pointer;
}

#bt-repor-mini3d:hover { border-color: var(--accent); color: var(--accent); }

@media (max-width: 900px) {
    #bt-repor-mini3d { left: auto; right: 8px; top: 56px; bottom: auto; }
    }

/* ---------------------------------- sliders em ecrã tátil (alvo maior) */

/* O polegar do sistema tem ~12px: num telemóvel é preciso acertar-lhe com um
   dedo de ~9mm. Aumentar obriga a desenhar a barra também (assim que se mexe
   no ::-webkit-slider-thumb, o accent-color deixa de pintar o resto). */
@media (pointer: coarse) {
    #slider-girar-3d,
    #controlos-3d-mais input[type="range"],
    #prop-opacidade,
    #prop-brilho {
        -webkit-appearance: none;
        appearance: none;
        height: 26px;
        background: transparent;
    }

    #slider-girar-3d::-webkit-slider-runnable-track,
    #controlos-3d-mais input[type="range"]::-webkit-slider-runnable-track,
    #prop-opacidade::-webkit-slider-runnable-track,
    #prop-brilho::-webkit-slider-runnable-track {
        height: 6px;
        border-radius: 999px;
        background: var(--fundo-fraco-2);
    }

    #slider-girar-3d::-webkit-slider-thumb,
    #controlos-3d-mais input[type="range"]::-webkit-slider-thumb,
    #prop-opacidade::-webkit-slider-thumb,
    #prop-brilho::-webkit-slider-thumb {
        -webkit-appearance: none;
        appearance: none;
        width: 24px;
        height: 24px;
        margin-top: -9px;
        border: 2px solid var(--sobre-accent);
        border-radius: 50%;
        background: var(--accent);
    }

    #slider-girar-3d::-moz-range-track,
    #controlos-3d-mais input[type="range"]::-moz-range-track,
    #prop-opacidade::-moz-range-track,
    #prop-brilho::-moz-range-track {
        height: 6px;
        border-radius: 999px;
        background: var(--fundo-fraco-2);
    }

    #slider-girar-3d::-moz-range-thumb,
    #controlos-3d-mais input[type="range"]::-moz-range-thumb,
    #prop-opacidade::-moz-range-thumb,
    #prop-brilho::-moz-range-thumb {
        width: 24px;
        height: 24px;
        border: 2px solid var(--sobre-accent);
        border-radius: 50%;
        background: var(--accent);
    }
}

/* ------------------------------------------- telemóvel deitado (paisagem) */

/* Em paisagem o ecrã é largo e BAIXO (~390px de altura no iPhone). Empilhar
   folha + tira de peças + barra de abas deixava o palco com ~100px, e os
   controlos flutuantes tapavam-no por inteiro: o utilizador mandou uma
   captura onde o modelo simplesmente não aparecia.
   Passa a organizar-se como um desktop pequeno — controlos à esquerda,
   modelo ao centro, secção ativa à direita, abas em baixo — que é o que a
   forma do ecrã pede. */
@media (max-width: 900px) and (orientation: landscape) {
    :root { --m-nav-h: 46px; --m-lateral: 232px; }

    /* a folha deixa de ser folha: vira coluna à direita, com altura toda */
    #painel,
    #painel-camadas {
        top: 56px;
        left: auto;
        right: 8px;
        bottom: calc(var(--m-nav-h) + 8px);
        width: var(--m-lateral);
        height: auto;
        border-radius: 14px;
        border: 1px solid var(--borda);
    }

    #editor-principal,
    #palco-principal {
        top: 56px;
        left: 8px;
        right: calc(var(--m-lateral) + 16px);
        bottom: calc(var(--m-nav-h) + 8px);
    }

    /* Alternador e lados do modelo encostam à esquerda e quebram em duas
       linhas: ao centro ficavam por cima do próprio modelo, que é o que se
       quer ver. */
    #barra-vistas {
        top: 62px;
        left: 16px;
        right: auto;
        justify-content: flex-start;
        padding-top: 0;
        max-width: 230px;
    }

    #alternador-vista,
    #vistas-camara { justify-content: flex-start; }

    #controlos-3d {
        left: 16px;
        right: auto;
        bottom: calc(var(--m-nav-h) + 16px);
        transform: none;
        width: min(240px, 34vw);
    }

    /* uma peça por linha (pedido do utilizador): em duas colunas os nomes
       longos ficavam cortados ("Manga izqui…") e a amostra minúscula */
    #zonas {
        flex-direction: column;
        flex-wrap: nowrap;
        overflow-x: hidden;
        overflow-y: auto;
        gap: 6px;
    }

    .zona {
        width: 100%;
        min-width: 0;
        flex: 0 0 auto;
        flex-direction: row;
        align-items: center;
        text-align: left;
        padding: 7px 9px;
    }

    .zona .etiqueta { font-size: 10px; max-width: none; }

    /* Cantos de baixo do palco, como no retrato — a regra do retrato ancora-se
       em --m-painel-h (altura da folha), que aqui é a altura da COLUNA da
       direita e punha a barra a meio do ecrã. */
    .editor-ferramentas { bottom: calc(var(--m-nav-h) + 16px); left: 16px; }

    #bt-recolher-folha {
        bottom: calc(var(--m-nav-h) + 8px);
        left: auto;
        right: calc(var(--m-lateral) + 16px);
        transform: none;
    }

    /* Recolher a folha em paisagem = fechar a coluna da direita. Sem isto o
       palco continuava com a faixa de 232px reservada e o botão só escondia
       a coluna, sem devolver o espaço a ninguém. */
    body.folha-recolhida { --m-lateral: 0px; }

    /* a tira baixa de "partes" não existe em paisagem: a coluna trata disso */
    body[data-secao-mobile="partes"] #painel { height: auto; }

    #painel-conteudo [data-secao="partes"] .painel-titulo { display: block; }

    #mini3d { display: none; }
}

/* --------------------------- janela flutuante do 3D (cabeçalho e estados) */

#mini3d-cabecalho {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 6px;
    height: 30px;
    padding: 0 3px 0 6px;
    box-sizing: border-box;
    background: var(--bg-elevado);
    border-bottom: 1px solid var(--borda);
    /* o arrasto vive aqui e só aqui — ver o comentário no index.php */
    cursor: grab;
    touch-action: none;
    user-select: none;
    -webkit-user-select: none;
}

#mini3d.a-arrastar #mini3d-cabecalho { cursor: grabbing; }

.mini3d-pega { display: flex; color: var(--texto-fraco); }

.mini3d-pega svg { width: 8px; height: 13px; }

.mini3d-titulo {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .04em;
    color: var(--texto);
}

.mini3d-acoes { margin-left: auto; display: flex; gap: 1px; }

.mini3d-acoes button {
    width: 24px;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: var(--texto-fraco);
    cursor: pointer;
}

.mini3d-acoes button:hover { background: var(--fundo-fraco-2); color: var(--texto); }

.mini3d-acoes svg { width: 13px; height: 13px; }

/* minimizada: fica só a barra de título, no sítio onde estava — a janela não
   desaparece do ecrã, senão perdia-se onde ela ficou */
#mini3d.minimizada { height: auto !important; }

#mini3d.minimizada #palco,
#mini3d.minimizada #mini3d-redimensionar { display: none; }

/* encaixe num canto: um realce curto para o gesto se ler como intencional */
#mini3d.encaixada { border-color: var(--accent); }

@media (pointer: coarse) {
    #mini3d-cabecalho { height: 36px; }
    .mini3d-acoes button { width: 30px; height: 30px; }
    .mini3d-acoes svg { width: 15px; height: 15px; }
    .mini3d-pega svg { width: 10px; height: 16px; }
}

/* ------------------------------------- menu de ações de uma camada (folha) */

#menu-camada { position: fixed; inset: 0; z-index: 30; }

.menu-camada-fundo { position: absolute; inset: 0; background: var(--scrim); }

.menu-camada-caixa {
    position: absolute;
    left: 50%;
    bottom: 0;
    transform: translateX(-50%);
    width: min(420px, 100%);
    box-sizing: border-box;
    padding: 8px 8px calc(8px + env(safe-area-inset-bottom));
    background: var(--bg-elevado);
    border: 1px solid var(--borda);
    border-radius: 16px 16px 0 0;
    box-shadow: var(--sombra-modal);
}

/* No ecrã largo a folha colada ao fundo ficava perdida num canto do monitor
   (chamado #115): passa a diálogo centrado. No telemóvel continua folha —
   é aí que o polegar a alcança. */
@media (min-width: 901px) {
    .menu-camada-caixa {
        bottom: auto;
        top: 50%;
        transform: translate(-50%, -50%);
        padding: 8px;
        border-radius: 16px;
    }
}

.menu-camada-titulo {
    padding: 8px 10px 10px;
    font-size: 12px;
    font-weight: 700;
    color: var(--texto-fraco);
    /* nome de ficheiro longo não pode empurrar a folha para fora */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.menu-camada-caixa button {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 13px 10px;
    font: inherit;
    font-size: 14px;
    text-align: left;
    border: 0;
    border-radius: 10px;
    background: transparent;
    color: var(--texto);
    cursor: pointer;
}

.menu-camada-caixa button:hover { background: var(--fundo-fraco); }

.menu-camada-ico { display: flex; color: var(--texto-fraco); }

.menu-camada-ico svg { width: 17px; height: 17px; }

/* O ⋮ está sempre visível, também no PC: a fila de ações do hover são ícones
   de 14px difíceis de ler, e o menu com rótulos é o caminho legível. A fila
   do hover continua a existir como atalho para quem já a conhece. */

@media (pointer: coarse) {
    /* alvos a sério: 14px de ícone com 22px de caixa não se acerta com o dedo */
    .camada-estado button { width: 34px; height: 34px; }

    .camada-estado svg { width: 17px; height: 17px; }

    .camada { padding: 4px 6px; }
}

/* ============================================ galeria de designs (galeria.php)

   Porta de entrada da rota: a lista do que já foi criado. Reaproveita os
   tokens e o cabeçalho do editor — só o miolo é próprio. */

/* Ficha simples do perfil (perfil.php) — linhas rótulo/valor. */
.conta-ficha {
    max-width: 480px;
    padding: 6px 16px;
    background: var(--bg-elevado);
    border: 1px solid var(--borda);
    border-radius: 12px;
}

.conta-ficha-linha {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 0;
    font-size: 13.5px;
}

.conta-ficha-linha + .conta-ficha-linha { border-top: 1px solid var(--borda); }

.conta-ficha-rotulo { color: var(--texto-fraco-2); font-weight: 600; }

body.pagina-galeria {
    overflow: auto;
    background: var(--bg);
}

.galeria {
    max-width: 1100px;
    margin: 0 auto;
    padding: 78px 16px 40px;
}

.galeria-cabecalho {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 18px;
}

.galeria-cabecalho h1 {
    flex: 1 1 auto;
    margin: 0;
    font-size: 20px;
}

.botao-criar {
    width: auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 0;
    padding: 10px 16px;
}

.botao-criar svg { width: 16px; height: 16px; }

.galeria-aviso {
    margin-bottom: 14px;
    padding: 10px 12px;
    font-size: 12.5px;
    color: var(--texto);
    background: var(--bg-sutil);
    border: 1px solid var(--borda);
    border-radius: 10px;
}

.galeria-vazia {
    padding: 48px 16px;
    text-align: center;
    color: var(--texto-fraco);
    background: var(--bg-sutil);
    border: 1px dashed var(--borda-forte);
    border-radius: 14px;
}

.galeria-grelha {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 14px;
}

.desenho-cartao {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--bg-elevado);
    border: 1px solid var(--borda);
    border-radius: 14px;
    overflow: hidden;
}

.desenho-cartao:hover { border-color: var(--accent); }

/* Caixa 4:3 fixa: a miniatura vem com o formato do palco onde foi tirada
   (retrato na janela flutuante, panorâmico no ecrã inteiro) e, sem a prender,
   cada cartão ficava com uma altura diferente. */
.desenho-imagem {
    position: relative;
    display: grid;
    place-items: center;
    aspect-ratio: 4 / 3;
    overflow: hidden;
    /* claro de propósito, como o palco — a foto do 3D vem com este fundo */
    background: var(--palco-bg);
}

.desenho-imagem img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.desenho-sem-imagem svg { width: 42px; height: 42px; color: var(--icone-inativo); }

.desenho-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 12px 12px;
}

.desenho-nome {
    font-size: 13.5px;
    font-weight: 700;
    color: var(--texto);
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.desenho-meta { font-size: 11px; color: var(--texto-fraco-2); }

/* ações do cartão: no rato só ao pairar; no toque sempre (senão não há forma
   de lá chegar) */
.desenho-acoes {
    position: absolute;
    top: 8px;
    right: 8px;
    display: none;
    gap: 4px;
}

.desenho-cartao:hover .desenho-acoes { display: flex; }

.desenho-acoes button {
    width: 30px;
    height: 30px;
    display: grid;
    place-items: center;
    padding: 0;
    color: #fff;
    background: var(--fundo-sobreposto);
    border: 0;
    border-radius: 8px;
    cursor: pointer;
}

.desenho-acoes button svg { width: 15px; height: 15px; }

.desenho-acoes .bt-apagar:hover { background: var(--perigo-forte); }

@media (pointer: coarse) {
    .desenho-acoes { display: flex; }
}

/* modal de criar: peça primeiro, depois como */

/* O contentor nunca teve regra própria — sem position/inset era um bloco
   normal no fim da página: aparecia encostado ao fundo à esquerda, sem scrim
   e sem centrar. Mesma anatomia dos outros modais (#modal-adicionar). */
#modal-criar {
    position: fixed;
    inset: 0;
    z-index: 32;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--scrim);
}

.caixa-criar { width: min(94vw, 520px); }

.criar-pecas {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 10px;
}

.criar-peca {
    padding: 16px 12px;
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    color: var(--texto);
    background: var(--bg-sutil);
    border: 1px solid var(--borda);
    border-radius: 12px;
    cursor: pointer;
}

.criar-peca:hover { border-color: var(--accent); background: var(--accent-fraco-2); }

#criar-erro,
#dialogo-erro {
    margin-top: 10px;
    padding: 8px 10px;
    font-size: 12px;
    color: var(--perigo);
    background: var(--perigo-fraco);
    border-radius: 8px;
}

/* diálogo próprio (renomear / apagar) — substitui prompt() e confirm() */
#modal-dialogo {
    position: fixed;
    inset: 0;
    z-index: 34;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--scrim);
}

.caixa-dialogo { width: min(94vw, 400px); }

#dialogo-campo {
    width: 100%;
    margin-top: 4px;
    padding: 9px 10px;
    font: inherit;
    font-size: 13px;
    color: var(--texto);
    background: var(--bg-sutil);
    border: 1px solid var(--borda-campo);
    border-radius: 8px;
    box-sizing: border-box;
    outline: none;
}

#dialogo-campo:focus { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-fraco-2); }

.dialogo-acoes {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 16px;
}

.dialogo-acoes button {
    padding: 8px 14px;
    font: inherit;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--texto);
    background: var(--bg-sutil);
    border: 1px solid var(--borda);
    border-radius: 9px;
    cursor: pointer;
}

.dialogo-acoes button:hover { border-color: var(--borda-forte); }

.dialogo-acoes button.principal {
    color: var(--sobre-accent);
    background: var(--accent);
    border-color: var(--accent);
}

.dialogo-acoes button.principal:hover { background: var(--accent-hover); }

/* --perigo-forte e não --perigo: o vermelho claro com texto branco por cima
   fica em 2,5:1, abaixo do mínimo legível. */
.dialogo-acoes button.principal.perigo {
    background: var(--perigo-forte);
    border-color: var(--perigo-forte);
    color: #fff;
}

.dialogo-acoes button:disabled { opacity: .55; cursor: default; }

@media (max-width: 900px) {
    .galeria { padding: 64px 12px 28px; }

    .galeria-cabecalho h1 { font-size: 17px; }

    .galeria-grelha { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
}
