/*
 * ProInsight Design System v1.0 (2026-09-12)
 * ============================================
 * Brand-grade design system integrating Tailwind (via CDN, sem build step —
 * Emenda 1.3.0) com componentes nativos, tokens de cor, e padrões reutilizáveis.
 * Base: Montserrat + palette de 5 cores semânticas (blue/violet/emerald/cyan/pink)
 * + laranja da marca (#D4912F) reservado só pra identidade/login.
 * Principle VII (Bugatti/getdesign adapted): densidade de dados + cores vivas.
 * Referência completa: DESIGN-SYSTEM.md e live canvas.
 */

/* ============================================================================
   FONTS & BASE
   ============================================================================ */

@font-face {
    font-family: "Montserrat App";
    src: url("/assets/fonts/montserrat-400.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Montserrat App";
    src: url("/assets/fonts/montserrat-800.woff2") format("woff2");
    font-weight: 800;
    font-style: normal;
    font-display: swap;
}

/* Fallback: browser usa 400 or 800 mais próximo para outros weights */

:root {
    /* Brand Colors */
    --proinsight-orange: #D4912F;
    --proinsight-ink: #0B0D0F;
    --proinsight-white: #FFFFFF;
    --proinsight-gray-100: #F4F5F6;

    /* Semantic Accents */
    --proinsight-blue: #3B82F6;      /* Revenue, primary metrics */
    --proinsight-violet: #8B5CF6;    /* Trends, analysis */
    --proinsight-emerald: #10B981;   /* Growth, positive indicators */
    --proinsight-cyan: #06B6D4;      /* Activity, engagement */
    --proinsight-pink: #EC4899;      /* Recommendations, high-value */

    /* Neutral Scale */
    --proinsight-neutral-900: #0B0D0F;
    --proinsight-neutral-700: #374151;
    --proinsight-neutral-400: #9CA3AF;
    --proinsight-neutral-200: #E5E7EB;
    --proinsight-neutral-50: #F9FAFB;

    /* Motion & Easing */
    --proinsight-ease-out: cubic-bezier(0.23, 1, 0.32, 1);
    --proinsight-transition-fast: 140ms var(--proinsight-ease-out);
    --proinsight-transition-normal: 200ms var(--proinsight-ease-out);
    --proinsight-transition-slow: 300ms var(--proinsight-ease-out);

    /* Escala "neutral" do Tailwind (pedido do usuário em 2026-09-16, ver
       seção THEMES abaixo) — valores idênticos à paleta padrão do Tailwind,
       só que como variável, pra lib/layout.php poder remapear
       bg-neutral-50/text-neutral-900/etc. por tema sem tocar nos templates.
       Tema "claro" = estes valores, é o que já era fixo antes. */
    --tw-neutral-50: #fafafa;
    --tw-neutral-100: #f5f5f5;
    --tw-neutral-200: #e5e5e5;
    --tw-neutral-300: #d4d4d4;
    --tw-neutral-400: #a3a3a3;
    --tw-neutral-500: #737373;
    --tw-neutral-600: #525252;
    --tw-neutral-700: #404040;
    --tw-neutral-800: #262626;
    --tw-neutral-900: #171717;
    --tw-neutral-950: #0a0a0a;

    /* Sidebar — sempre escura nos 4 temas, mas com a cor do "chrome" própria
       por tema (não usa a escala --tw-neutral-*, que é do conteúdo
       principal). Tema "claro" ajustado em 2026-09-19 (pacote de handoff
       `07-direcao-visual-imagem-2.md`, direção aprovada "imagem 2") de um
       cinza neutro (#333333) pra um grafite mais frio (#202123–#292A2D) —
       bg mais escuro, hover no limite superior da faixa, mantendo a mesma
       relação bg/border/hover/muted que já existia. Os outros 3 temas não
       fazem parte da direção aprovada (que só especifica o tema claro) e
       mantêm seus tons próprios. */
    --ph-sidebar-bg: #202123;
    --ph-sidebar-border: #3a3b40;
    --ph-sidebar-muted: #9a9ba3;
    --ph-sidebar-hover: #292a2d;

    /* Elementos estruturais dos gráficos SVG (grade, rótulos, linha de
       média) — ver .chart-grid-linha etc. em COMPONENTS: Charts. */
    --chart-grid: #e5e5e5;
    --chart-muted: #a3a3a3;
    --chart-muted-forte: #525252;

    /* Tokens semânticos novos (2026-09-19, pacote de handoff
       `07-direcao-visual-imagem-2.md`) — só valem no tema "claro"; os
       outros 3 temas preservam contraste/hierarquia sem precisar bater
       nesses hex exatos (a direção aprovada só especifica o tema claro).
       Propositalmente separados da paleta categórica dos gráficos/KPIs
       (--proinsight-blue/emerald/etc., que tem significado fixo por tipo
       de dado, ver DESIGN-SYSTEM.md) — estes aqui são de UI/status, não de
       série de dado. */
    --ph-page-bg: #F7F8FA;
    --ph-border: #E2E6EC;
    --ph-text-secondary: #667085;
    --ph-focus: #2F6FED;
    --ph-status-info: #2F6FED;
    --ph-status-success: #0A8F5B;
    /* rgba translúcido em vez de hex sólido claro (#EAF7F1) — se adapta
       sozinho a fundo claro OU escuro sem precisar de override por tema
       (ver html[data-theme=...] mais abaixo: nenhum dos 3 temas escuros
       sobrescreve isso, de propósito). */
    --ph-status-success-surface: rgba(10, 143, 91, 0.14);
    /* Não existia variante de erro/perigo semântica antes desta fundação —
       `.alert-warning` reaproveitava o rosa categórico (--proinsight-pink,
       que na verdade significa "recomendações de alto valor" em
       DESIGN-SYSTEM.md), sem vermelho de verdade em lugar nenhum. Fica
       pronta aqui pra Issue 5 (zona de perigo do import, erros de
       validação) usar — "não usar laranja pra erro, usar vermelho
       semântico com ícone + texto" (checklist de QA). */
    --ph-status-danger: #B42318;
    --ph-status-danger-surface: rgba(180, 35, 24, 0.12);
    --ph-brand-surface: rgba(212, 145, 47, 0.1);
    /* Laranja da marca (--proinsight-orange, #D4912F) tem contraste ~2.66:1
       sobre branco — falha AA mesmo em texto grande (auditoria
       02-auditoria-ux-ui-a11y.md). Usar --ph-brand-text em vez do laranja
       puro sempre que ele for cor de TEXTO/ícone pequeno sobre claro; o
       laranja puro continua correto como fundo de botão escuro, glow sobre
       fundo escuro (login) ou elemento não-textual grande. */
    --ph-brand-text: #9A5B0E;

    /* Fundação de consistência (auditoria sistêmica 2026-09-20) — até aqui só
       cor e motion eram tokens; espaçamento/tamanho de fonte/radius/sombra
       eram valores soltos repetidos por componente (mesmo 0.5rem de radius
       escrito em dezenas de lugares, por exemplo). Nomear esses valores aqui
       não muda nada visualmente por si só — só dá um lugar único pra mudar no
       futuro. Aplicados nos componentes mais duplicados logo abaixo (Cards,
       KPIs, badges/chips, overlays), não reescritos no arquivo inteiro: um
       arquivo CSS sem build/lint não tem rede de segurança pra uma
       substituição em massa sem risco de regressão visual silenciosa. */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.25rem;
    --space-6: 1.5rem;
    --space-8: 2rem;

    --font-size-display: 3rem;      /* 48px */
    --font-size-h1: 2rem;           /* 32px */
    --font-size-h2: 1.5rem;         /* 24px */
    --font-size-h3: 1.125rem;       /* 18px */
    --font-size-body-lg: 1rem;      /* 16px */
    --font-size-body: 0.875rem;     /* 14px */
    --font-size-body-sm: 0.75rem;   /* 12px */
    --font-size-caption: 0.6875rem; /* 11px */
    --font-size-button: 0.8125rem;  /* 13px */

    --radius-sm: 0.25rem;
    --radius-md: 0.375rem;
    --radius-lg: 0.5rem;
    --radius-xl: 0.75rem;
    --radius-pill: 9999px;

    --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
    --shadow-lg: 0 12px 28px rgba(0, 0, 0, 0.18);
    --shadow-xl: 0 24px 48px rgba(0, 0, 0, 0.25);

    /* Overlays usavam números soltos sem relação declarada entre si
       (40/999/1000/1100/1200) — nomeados na ordem de empilhamento real. */
    --z-sticky: 5;
    --z-dropdown: 40;
    --z-overlay: 999;
    --z-tooltip: 1000;
    --z-modal: 1100;
    --z-modal-top: 1200;

    /* .rank-badge-padrao/.rank-top10-chip duplicavam este mesmo par de hex
       (neutro genérico, não faz parte da paleta semântica/de marca). */
    --ph-neutral-chip-bg: #F3F4F6;
    --ph-neutral-chip-text: #6B7280;
}

/* ============================================================================
   THEMES (pedido do usuário em 2026-09-16) — "claro" é o :root acima (sem
   atributo, ou data-theme="claro"); os 3 abaixo mudam só o "chrome" (fundo,
   texto, bordas, sidebar, grade dos gráficos) — o laranja da marca
   (--proinsight-orange) e as cores semânticas dos gráficos/badges
   (--proinsight-blue/violet/emerald/cyan/pink, corMarca() em chart.php)
   ficam fixos nos 4, de propósito: são a identidade e o código de cor dos
   dados, não deveriam mudar com o gosto de tema de cada um. Ativado via
   `<html data-theme="...">` (lib/layout.php::temaAtual(), cookie
   `ph_tema`) + seletor em app.js. Cada tema redefine as mesmas variáveis
   do :root, então qualquer classe/componente que já usa var(--tw-neutral-*)
   ou var(--proinsight-*) fica "de graça" tematizado.
   ============================================================================ */

html[data-theme="escuro"] {
    --proinsight-white: #1a1a1d;
    --proinsight-neutral-900: #f3f4f6;
    --proinsight-neutral-700: #c7cbd1;
    --proinsight-neutral-400: #7d8590;
    --proinsight-neutral-200: #2a2e33;
    --proinsight-neutral-50: #17191c;

    --tw-neutral-50: #0d0d0e;
    --tw-neutral-100: #151517;
    --tw-neutral-200: #232326;
    --tw-neutral-300: #313135;
    --tw-neutral-400: #96979c;
    --tw-neutral-500: #a9aaae;
    --tw-neutral-600: #bcbdc1;
    --tw-neutral-700: #d0d1d3;
    --tw-neutral-800: #e3e4e5;
    --tw-neutral-900: #f5f5f6;
    --tw-neutral-950: #ffffff;

    --ph-sidebar-bg: #1f1f1f;
    --ph-sidebar-border: #3a3a3a;
    --ph-sidebar-muted: #9a9a9a;
    --ph-sidebar-hover: #333333;

    --chart-grid: #2a2a2d;
    --chart-muted: #8a8d92;
    --chart-muted-forte: #c2c4c8;

    /* Tokens novos de #141 (definidos só no tema claro) que falham
       contraste herdando o valor claro num fundo escuro — reaproveita a
       escala de neutro já calibrada deste tema em vez de inventar um valor
       novo. --ph-focus/--ph-status-info/--ph-status-danger/--ph-border não
       precisaram de override (ver issue #157: já passam contraste no uso
       real atual, ou ainda não têm uso real no código). */
    --ph-text-secondary: var(--proinsight-neutral-400);
    --ph-brand-text: var(--proinsight-orange);
}

html[data-theme="meia-noite"] {
    --proinsight-white: #101a2c;
    --proinsight-neutral-900: #f2f4f8;
    --proinsight-neutral-700: #c4cadc;
    --proinsight-neutral-400: #7e88a3;
    --proinsight-neutral-200: #232c46;
    --proinsight-neutral-50: #0d1424;

    --tw-neutral-50: #060a14;
    --tw-neutral-100: #0c1220;
    --tw-neutral-200: #1a2338;
    --tw-neutral-300: #29314c;
    --tw-neutral-400: #8891a8;
    --tw-neutral-500: #9aa3b8;
    --tw-neutral-600: #b0b8c9;
    --tw-neutral-700: #c7ccdb;
    --tw-neutral-800: #dee1e9;
    --tw-neutral-900: #f2f4f8;
    --tw-neutral-950: #ffffff;

    --ph-sidebar-bg: #0b1220;
    --ph-sidebar-border: #24304a;
    --ph-sidebar-muted: #8c96b0;
    --ph-sidebar-hover: #1b2740;

    --chart-grid: #202a42;
    --chart-muted: #7e88a8;
    --chart-muted-forte: #b7bfd6;

    /* Ver comentário equivalente no tema "escuro" acima. */
    --ph-text-secondary: var(--proinsight-neutral-400);
    --ph-brand-text: var(--proinsight-orange);
}

html[data-theme="petroleo"] {
    --proinsight-white: #0d211d;
    --proinsight-neutral-900: #eff5f3;
    --proinsight-neutral-700: #bfd1cc;
    --proinsight-neutral-400: #75948d;
    --proinsight-neutral-200: #1d302c;
    --proinsight-neutral-50: #0a1614;

    --tw-neutral-50: #05100e;
    --tw-neutral-100: #0a1917;
    --tw-neutral-200: #172926;
    --tw-neutral-300: #253a36;
    --tw-neutral-400: #86a29c;
    --tw-neutral-500: #98b2ac;
    --tw-neutral-600: #adc3be;
    --tw-neutral-700: #c4d4d0;
    --tw-neutral-800: #dbe6e3;
    --tw-neutral-900: #f0f5f4;
    --tw-neutral-950: #ffffff;

    --ph-sidebar-bg: #081714;
    --ph-sidebar-border: #1f332f;
    --ph-sidebar-muted: #85a29b;
    --ph-sidebar-hover: #12241f;

    --chart-grid: #1c2f2b;
    --chart-muted: #7c9c95;
    --chart-muted-forte: #b6cdc7;

    /* Ver comentário equivalente no tema "escuro" acima. */
    --ph-text-secondary: var(--proinsight-neutral-400);
    --ph-brand-text: var(--proinsight-orange);
}

body {
    font-family: "Montserrat App", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    background-color: var(--ph-page-bg);
    color: var(--proinsight-neutral-900);
}

/* Rede de segurança contra overflow horizontal (auditoria sistêmica
   2026-09-20): nenhuma <img> sem classe própria tinha proteção contra
   estourar a largura do container em telas estreitas. Componentes que já
   definem sua própria regra de imagem (`.foto-produto-botao img`,
   `.ph-tutorial-passo-imagem`, `.ph-lightbox-figura img`) continuam
   funcionando iguais — `max-width` aqui só cobre o que não tinha nada. */
img {
    max-width: 100%;
    height: auto;
}

/* Tailwind não sabe da fonte da marca — usar `class="font-brand"` em títulos/logo. */
.font-brand {
    font-family: "Montserrat App", system-ui, sans-serif;
}

/* ============================================================================
   COMPONENTS: Cards & Containers
   ============================================================================ */

/* Base card: white background, subtle border, soft shadow */
.ph-card {
    background-color: var(--proinsight-white);
    border: 1px solid var(--proinsight-neutral-200);
    border-radius: var(--radius-lg);
    padding: var(--space-6);
    box-shadow: var(--shadow-sm);
}

/* Card with elevation: for product cards & interactive elements */
.ph-card-elevated {
    border: 1px solid var(--proinsight-neutral-200);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
}

/* Seção "hero" de uma tela (ex. gráfico de compras por mês em detalhe.php) —
   estende .ph-card-elevated com uma borda superior de cor; declarada depois
   dela no arquivo de propósito, pra vencer o `border` shorthand da classe
   base na cascata (mesma especificidade, ordem de declaração decide). */
.ph-hero-section {
    background: var(--proinsight-white);
    padding: 1.5rem;
    border-top: 3px solid var(--proinsight-blue);
}

/* Variante "IA" do hero-section (pedido do usuário em 2026-09-17: destacar
   fortemente a seção de Sugestões de venda como a mais "IA" da tela) — borda
   superior na cor de identidade de IA (laranja, mesma usada nos selos "IA"
   do resto da página) em vez do azul/violeta das seções de gráfico.
   Declarada depois de `.ph-hero-section` de propósito, mesma razão do
   comentário acima (vencer o `border-top` na cascata).

   Pedido do usuário em 2026-09-19 pra destacar ainda mais essa área ("dar um
   glow"): anel de sombra laranja que pulsa pra fora, mesma técnica de
   `kpi-pulse-azul`/`kpi-pulse-violeta` (linha ~1349) — só que combinando com
   a sombra base do card (herdada de `.ph-card-elevated`) em vez de
   substituí-la, já que aqui o elemento já tem `box-shadow` próprio. */
/* O anel que PULSA (se expande e desaparece) segue só na entrada (3 ciclos,
   ~7s) — auditoria 02-auditoria-ux-ui-a11y.md sinalizou o glow contínuo
   PULSANTE como distração (Principle VIII pede transição de entrada, não
   pulsação eterna). Isso é diferente de um glow permanente e ESTÁTICO (sem
   movimento): pedido do usuário em 2026-09-19 ("faça um glow permanente")
   — adicionada uma 3ª camada de box-shadow (`0 0 18px`, difusa, sem anel)
   que não faz parte da animação e por isso fica sempre visível, inclusive
   depois que o pulso de entrada termina (e com `prefers-reduced-motion`,
   que desliga a `animation` mas não este box-shadow base). */
.ph-hero-section-ia {
    border-top: 3px solid var(--proinsight-orange);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08), 0 0 18px rgba(212, 145, 47, 0.45);
    animation: ph-hero-ia-pulse 2.4s ease-in-out 3;
}

@keyframes ph-hero-ia-pulse {
    0%, 100% { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08), 0 0 18px rgba(212, 145, 47, 0.45), 0 0 0 0 rgba(212, 145, 47, 0.35); }
    50% { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08), 0 0 18px rgba(212, 145, 47, 0.45), 0 0 0 10px rgba(212, 145, 47, 0); }
}

.ph-card-interativo {
    transition: box-shadow var(--proinsight-transition-normal),
                border-color var(--proinsight-transition-normal);
    cursor: pointer;
}

.ph-card-interativo:hover {
    border-color: var(--proinsight-neutral-400);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
}

.ph-card-interativo:focus-visible {
    outline: 2px solid var(--ph-focus);
    outline-offset: 2px;
}

/* Hero de apresentação acima de "Clientes" (redesign 2026-09-19, substitui o
   ".ph-ia-hint" anterior — pedido do usuário: "não quero mais aquela
   sequência de caixinhas Histórico + Estoque + Ofertas + IA -> Pedido",
   "não quero que isso pareça um card tradicional"). Ganhou um destaque de
   fundo próprio em 2026-09-20 (pedido do usuário, ver .ph-hero-painel
   abaixo) — a separação de "Clientes" logo abaixo continua vindo só da
   margem (clientes/index.php), não de um contorno duplicado. */

/* Painel do hero — gradiente tonal na cor de marca (não um preenchimento
   sólido) + borda fina, sem box-shadow: dá presença de fundo sem virar o
   "card tradicional" que o usuário tinha pedido pra tirar no redesign
   anterior. Cantos bem arredondados (rounded-3xl no HTML) pra destoar dos
   `.ph-card` (rounded-2xl) do resto da tela — reforça que é uma seção de
   apresentação, não mais um card de dado. */
.ph-hero-painel {
    background: linear-gradient(135deg, rgba(212, 145, 47, 0.10), rgba(212, 145, 47, 0.02) 60%, transparent 100%);
    border: 1px solid rgba(212, 145, 47, 0.14);
}

.ph-hero-ia-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ph-brand-text);
}

/* Único trecho da headline em laranja — "a palavra relacionada a
   IA/oportunidades pode receber destaque", o resto do H1 fica na cor de
   texto padrão (herdada). --ph-brand-text em vez do laranja puro: mesmo em
   texto grande (H1), #D4912F sobre branco falha AA (~2.66:1, precisa 3:1). */
.ph-hero-ia-destaque {
    color: var(--ph-brand-text);
}

/* Glifo decorativo à direita do hero (pedido do usuário: "extremamente
   discreto") — o mesmo ícone de estrela dos selos de IA, só que gigante e
   quase invisível (12% de opacidade), puramente ilustrativo (aria-hidden
   no HTML). Some abaixo de `lg` pra não competir com o texto em telas
   estreitas. */
.ph-hero-ia-glifo {
    position: relative;
}

/* Achado ao testar a animação de entrada (2026-09-21): os 3 pontinhos de
   brilho (.ph-hero-spark abaixo) precisam ficar FORA de um elemento com
   opacity:0.12 — opacity de um ancestral se multiplica com a do
   descendente, então um spark que anima até opacity:1 renderizava a
   0.12 de verdade (12% de 100%), invisível. Por isso a cor/opacidade do
   glifo (só do ícone em si) mora num wrapper interno próprio
   (.ph-hero-ia-glifo-icone), enquanto os sparks ficam como irmãos dele,
   direto dentro de .ph-hero-ia-glifo (sem opacity reduzida). */
.ph-hero-ia-glifo-icone {
    color: var(--proinsight-orange);
    opacity: 0.12;
}

.ph-hero-ia-glifo-icone svg {
    width: 4.5rem;
    height: 4.5rem;
    stroke-width: 1;
}

/* Animação de entrada do hero (pedido do usuário em 2026-09-21) — roda UMA
   vez ao carregar a página, nunca em loop. app.js ("Animação de entrada do
   hero") adiciona a classe .ph-hero-anim-ativo em .ph-hero-painel no
   DOMContentLoaded; sem essa classe (JS desabilitado, ou antes de rodar),
   título e glifo ficam exatamente como sempre foram — só não há a
   flourish de entrada, nada fica permanentemente escondido. */

/* Palavra a palavra do H1 (fade-in + leve subida) — cada
   <span class="ph-hero-word"> recebe um animation-delay inline sequencial
   (clientes/index.php), incluindo as palavras de dentro de
   .ph-hero-ia-destaque — que por já serem as últimas da frase entram por
   último naturalmente, sem precisar de nenhum caso especial aqui. */
.ph-hero-word {
    display: inline-block;
}

.ph-hero-anim-ativo .ph-hero-word {
    opacity: 0;
    transform: translateY(0.3em);
    animation: ph-hero-word-in 0.5s ease-out forwards;
}

@keyframes ph-hero-word-in {
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* Estrela: gira + pulsa uma vez (scale + rotate) na entrada, terminando no
   mesmo tamanho/opacidade discretos de sempre (0.12, ver
   .ph-hero-ia-glifo-icone acima) — só o instante da entrada fica mais
   visível. Anima o WRAPPER (.ph-hero-ia-glifo-icone), não o <svg> dentro
   dele — a keyframe de opacity abaixo substitui a opacity:0.12 estática
   desse mesmo elemento (não multiplica com ela, já que é a mesma
   propriedade no mesmo elemento); animar o filho <svg> em vez do wrapper
   faria a opacity animada MULTIPLICAR pela opacity:0.12 estática do
   ancestral (mesmo bug que os sparks tinham, ver comentário acima),
   deixando o pico da animação quase tão apagado quanto o repouso. */
.ph-hero-anim-ativo .ph-hero-ia-glifo-icone {
    animation: ph-hero-star-in 0.8s ease-out 1;
}

@keyframes ph-hero-star-in {
    0% { opacity: 0; transform: scale(0.5) rotate(-35deg); }
    55% { opacity: 0.6; transform: scale(1.18) rotate(10deg); }
    100% { opacity: 0.12; transform: scale(1) rotate(0deg); }
}

/* 3 pontinhos de brilho soltos pela estrela em sequência (~0.15s entre
   eles) — nascem e somem uma vez só, nunca em loop. Posicionados ao redor
   do glifo, que já tem position: relative acima. */
.ph-hero-spark {
    position: absolute;
    width: 6px;
    height: 6px;
    border-radius: 9999px;
    background: var(--proinsight-orange);
    opacity: 0;
    pointer-events: none;
}

.ph-hero-anim-ativo .ph-hero-spark {
    animation: ph-hero-spark-pop 0.55s ease-out 1;
}

.ph-hero-spark-1 {
    top: 0;
    right: 0.75rem;
}

.ph-hero-spark-2 {
    top: 55%;
    right: -0.5rem;
}

.ph-hero-spark-3 {
    bottom: 0.5rem;
    right: 1.25rem;
}

/* animation-delay por spark precisa da MESMA especificidade de 2 classes
   de ".ph-hero-anim-ativo .ph-hero-spark" acima (não só ".ph-hero-spark-N"
   sozinho, 1 classe) — senão o "animation-delay: 0s" implícito no shorthand
   "animation: ..." daquela regra (mais específica) ganha e os 3 pontinhos
   disparam todos juntos, sem sequência nenhuma (achado ao testar). */
.ph-hero-anim-ativo .ph-hero-spark-1 {
    animation-delay: 0.3s;
}

.ph-hero-anim-ativo .ph-hero-spark-2 {
    animation-delay: 0.45s;
}

.ph-hero-anim-ativo .ph-hero-spark-3 {
    animation-delay: 0.6s;
}

@keyframes ph-hero-spark-pop {
    0% { opacity: 0; transform: scale(0); }
    45% { opacity: 1; transform: scale(1.3); }
    100% { opacity: 0; transform: scale(0.3); }
}

@media (prefers-reduced-motion: reduce) {
    .ph-hero-anim-ativo .ph-hero-word {
        animation: none;
        opacity: 1;
        transform: none;
    }

    .ph-hero-anim-ativo .ph-hero-ia-glifo-icone {
        animation: none;
    }

    .ph-hero-anim-ativo .ph-hero-spark {
        animation: none;
        opacity: 0;
    }
}

/* Divisor sutil entre os indicadores inline do header de clientes (125
   clientes · R$ X em compras · N oportunidades) — só um caractere, sem
   borda/pill, pra não parecer badge. */
.ph-stat-divisor {
    color: var(--proinsight-neutral-200);
}

/* Paginação da listagem de clientes (pedido do usuário em 2026-09-20:
   "batches de 10 clientes") — botões discretos, mesma linguagem visual
   dos outros controles pequenos da toolbar (borda fina + hover sutil), o
   número da página ativa usa o mesmo tratamento laranja translúcido do
   filtro "Ordenar por"/badges de IA do resto do app. */
/* Alvo de toque: 2rem/32px original ficava abaixo do mínimo confortável.
   Não subiu pros 2.75rem/44px usados em botões isolados (ver
   .ph-lightbox-fechar/.ph-tutorial-fechar acima) de propósito — numa fileira
   densa com vários números de página, isso alargaria demais a barra em
   telas de 320-375px. 2.5rem já é uma melhora real (+25%) mantendo a fileira
   estreita; `flex-wrap` no container (clientes/index.php) segura o caso de
   ainda não caber, em vez de causar scroll horizontal. */
.ph-paginacao-botao {
    display: inline-flex;
    height: 2.5rem;
    width: 2.5rem;
    align-items: center;
    justify-content: center;
    border-radius: 0.5rem;
    border: 1px solid var(--proinsight-neutral-200);
    background: var(--proinsight-white);
    color: var(--ph-text-secondary);
    transition: border-color var(--proinsight-transition-fast),
                color var(--proinsight-transition-fast);
}

.ph-paginacao-botao:hover:not(:disabled) {
    border-color: var(--proinsight-neutral-400);
    color: var(--proinsight-neutral-700);
}

.ph-paginacao-botao:focus-visible {
    outline: 2px solid var(--ph-focus);
    outline-offset: 2px;
}

.ph-paginacao-botao:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.ph-paginacao-numero {
    display: inline-flex;
    height: 2.5rem;
    min-width: 2.5rem;
    align-items: center;
    justify-content: center;
    padding: 0 0.5rem;
    border-radius: 0.5rem;
    border: 1px solid transparent;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--ph-text-secondary);
}

.ph-paginacao-numero:hover:not(.is-ativa) {
    background: var(--proinsight-neutral-50);
}

.ph-paginacao-numero:focus-visible {
    outline: 2px solid var(--ph-focus);
    outline-offset: 2px;
}

.ph-paginacao-numero.is-ativa {
    border-color: rgba(212, 145, 47, 0.35);
    background: rgba(212, 145, 47, 0.1);
    color: var(--ph-brand-text);
}

.ph-paginacao-reticencias {
    display: inline-flex;
    height: 2.5rem;
    min-width: 1.25rem;
    align-items: center;
    justify-content: center;
    color: var(--proinsight-neutral-400);
    font-size: 0.8125rem;
}

/* KPI Card: metric display with colored bar accent */
.kpi-card {
    background: var(--proinsight-white);
    border: 1px solid var(--proinsight-neutral-200);
    border-radius: var(--radius-lg);
    padding: var(--space-5);
}

.kpi-label {
    font-size: 0.6875rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.025em;
    color: var(--ph-text-secondary);
    margin-bottom: 0.5rem;
}

.kpi-value {
    font-size: 1.75rem;
    font-weight: 800;
    color: var(--proinsight-neutral-900);
    margin-bottom: 0.75rem;
    line-height: 1.1;
}

.kpi-bar {
    height: 0.25rem;
    background: var(--proinsight-neutral-200);
    border-radius: 9999px;
    overflow: hidden;
    margin-bottom: 0.5rem;
}

.kpi-fill {
    height: 100%;
    border-radius: 9999px;
    transition: width var(--proinsight-transition-normal);
}

.kpi-detail {
    font-size: 0.75rem;
    color: var(--proinsight-neutral-700);
}

/* KPI Hero: a métrica mais importante da tela (1 por tela) — maior, com
   fundo tonal sutil e borda de cor, pra romper a monotonia de "todo card
   igual" (revisão de design 2026-09-12). Conteúdo centralizado na vertical
   (pedido do usuário em 2026-09-17) — o grid ao lado ficou mais alto depois
   dos KPIs de Meta/Supermeta (6 cards em 2 linhas em vez de 4 numa linha só),
   e o Grid por padrão estica os itens pra acompanhar a altura da linha
   (`align-items: stretch`), deixando um vão em branco embaixo do valor. */
.kpi-hero {
    display: flex;
    flex-direction: column;
    justify-content: center;
    border-radius: var(--radius-xl);
    padding: var(--space-6);
    border: 1px solid;
    /* Container query, não media query, pro font-size de .kpi-hero-value
       abaixo (auditoria de mobile 2026-09-20, ver comentário lá) — a
       largura desta coluna no grid 3:1 (.mt-4.grid.sm:grid-cols-3 em
       detalhe.php) não varia de forma monótona com a viewport (a sidebar
       fixa entra em lg=1024px e na prática ENCOLHE a coluna nesse ponto),
       então uma media query por viewport não consegue acompanhar — medir a
       largura real do próprio card é a única forma robusta. */
    container-type: inline-size;
}

.kpi-hero-label {
    font-size: 0.6875rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.kpi-hero-value {
    /* Reduzido de 2.5rem e com nowrap (pedido do usuário em 2026-09-15:
       "não quebre os números") — valores de 8 dígitos como
       "R$ 3.439.363,32" quebravam em duas linhas no card estreito
       (col-span-1 de 3, ver comentário em clientes/detalhe.php). Sem
       truncar/escurecer o valor, só um tamanho que cabe numa linha só. */
    font-size: 1.875rem;
    font-weight: 800;
    line-height: 1.15;
    letter-spacing: -0.01em;
    color: var(--proinsight-neutral-900);
    margin-top: 0.375rem;
    white-space: nowrap;
}

/* Rede de segurança por CONTAINER, não por viewport (auditoria de mobile
   2026-09-20, achado via Playwright): o tamanho acima cabe numa coluna
   larga, mas na grade 3:1 (.mt-4.grid.sm:grid-cols-3 em detalhe.php) esse
   card fica estreito numa faixa enorme e NÃO-MONÓTONA de larguras de tela
   (confirmado de verdade: ~640-1200px vazava/sobrepunha o card vizinho, com
   1024px — onde a sidebar fixa liga — sendo mais estreito que 900px, não
   mais largo). Uma media query por viewport não tem como acompanhar essa
   relação; container query mede a largura real do próprio `.kpi-hero`
   (`container-type: inline-size` ali) e funciona não importa a causa do
   aperto. */
@container (max-width: 250px) {
    .kpi-hero-value {
        font-size: 1.375rem;
    }
}

@container (max-width: 160px) {
    .kpi-hero-value {
        font-size: 1rem;
    }
}

.kpi-hero-blue {
    background: linear-gradient(180deg, rgba(59, 130, 246, 0.08), rgba(59, 130, 246, 0.02));
    border-color: rgba(59, 130, 246, 0.25);
}

.kpi-hero-blue .kpi-hero-label {
    color: var(--proinsight-blue);
}

/* Tingimento leve dos cards de Meta/Supermeta (pedido do usuário em
   2026-09-19: "aplique background em meta e supermeta de acordo com o
   conteúdo da pasta novas_imagens") — as duas artes SVG de lá
   (meta-target-bg.svg, em branco 20% opacidade; supermeta-trophy-bg.svg, em
   laranja da marca) foram desenhadas pra sentar sobre um fundo com alguma
   cor, não branco puro (`.ph-card` normal) — a de branco ficaria invisível.
   Corrigido no mesmo dia (achado do próprio usuário: "o tema padrão é
   claro, precisa ser visto em todos os temas") — a primeira versão só
   tinha o gradiente translúcido como background, SEM nenhuma camada opaca
   por baixo; como o card fica sobre `body`/`--ph-page-bg` (nunca
   sobrescrito pelos 3 temas escuros, só a classe Tailwind `bg-neutral-50`
   do body é), o resultado variava com o que estivesse atrás em vez de com
   a cor de "superfície de card" do tema atual. Adicionando
   `var(--proinsight-white)` como camada de baixo (a mesma cor que
   `.ph-card` normal usa) o card fica opaco e no tom certo de cada tema — o
   gradiente por cima só acrescenta o tingimento de cor. */
/* Destaque reforçado (pedido do usuário em 2026-09-19: "inserir uma cor
   forte e glow... quero dar bastante destaque") — tingimento mais saturado
   (diagonal em vez de vertical, pra dar mais volume), borda na cor da marca
   em vez da borda neutra padrão do .ph-card, e um glow permanente (não só o
   pulso de entrada do .kpi-pulse-*) pra ficar em destaque o tempo todo, não
   só nos 3 ciclos iniciais. */
.kpi-card-tint-blue {
    background: linear-gradient(135deg, rgba(37, 99, 235, 0.22), rgba(37, 99, 235, 0.04) 65%), var(--proinsight-white);
    border-color: rgba(37, 99, 235, 0.4);
    box-shadow: 0 0 0 1px rgba(37, 99, 235, 0.06), 0 10px 30px -10px rgba(37, 99, 235, 0.45);
}

.kpi-card-tint-violet {
    background: linear-gradient(135deg, rgba(139, 92, 246, 0.22), rgba(139, 92, 246, 0.04) 65%), var(--proinsight-white);
    border-color: rgba(139, 92, 246, 0.4);
    box-shadow: 0 0 0 1px rgba(139, 92, 246, 0.06), 0 10px 30px -10px rgba(139, 92, 246, 0.5);
}

/* KPI "Marca mais comprada" (pedido do usuário em 2026-09-19; fundo sólido
   pedido em 2026-09-21) — a cor vem de corMarca() em lib/chart.php (a
   MESMA função que colore a linha dessa marca no gráfico "Compras por mês,
   por marca"), passada inline via `--marca-cor` porque é arbitrária (hex
   da tabela de marca ou darkgray de fallback, não um dos 5 tons fixos do
   resto do app). Card inteiro preenchido (gradiente sutil da própria cor
   pra uma versão mais escura dela mesma, via color-mix — nunca duas cores
   arbitrárias diferentes) com texto branco por cima (padrão pedido pelo
   usuário junto da tabela de cores) — ao contrário de .chart-legenda-item
   (linha ~1559), que só tinge a borda/fundo com color-mix sobre os
   tokens do tema porque a cor ali é só um acento, não o card inteiro. */
.kpi-card-marca {
    background: linear-gradient(135deg, var(--marca-cor) 0%, color-mix(in srgb, var(--marca-cor) 72%, black) 100%);
    border-color: color-mix(in srgb, var(--marca-cor) 55%, black);
    box-shadow: 0 10px 24px -12px color-mix(in srgb, var(--marca-cor) 55%, transparent);
}

.kpi-card-marca .text-ph-secondary {
    color: rgba(255, 255, 255, 0.82);
}

.kpi-card-marca-icone {
    background: rgba(255, 255, 255, 0.22);
    color: #FFFFFF;
}

.kpi-card-marca-valor {
    /* Branco literal, não var(--proinsight-white) — esse token é uma
       superfície de fundo que nos temas escuros vira uma cor ESCURA
       (#1a1a1d/#101a2c/#0d211d), não literalmente branca; ficaria
       invisível sobre o gradiente de --marca-cor. */
    color: #FFFFFF;
}

/* Colunas "Representante"/"Marca preferida" da listagem de clientes
   (public_html/clientes/index.php, pedido do usuário em 2026-09-21) —
   largura FIXA declarada aqui (CSS síncrono), não `max-w-[Nrem]` do
   Tailwind: representante pode vir com vários nomes colados por "/" sem
   espaço (ex. "DIEGO/SHAO/CELIO", uma string sem ponto de quebra), e o
   valor original (max-width só no texto, sem width fixa no container)
   deixava a coluna crescer e estourar a linha pra esse caso. Com width
   fixa + overflow hidden no container, a coluna nunca passa desse tamanho
   não importa o texto — trunca com segurança, mesmo sem espaço nenhum pra
   quebrar.

   9rem -> 7rem (2026-09-21, segunda rodada): com 3 colunas fixas (esta +
   Comprado + Marca preferida) mais o nome ainda travado em 24rem, a soma
   passava do espaço disponível dentro de max-w-6xl (lib/layout.php,
   1152px) e "Ver detalhes" era empurrado pra fora do card (achado por
   screenshot do usuário) — 7rem some espaço + o nome virar flexível
   (.cliente-lista-nome abaixo) resolve isso com folga. */
.cliente-coluna-truncada {
    flex: 0 0 7rem;
    width: 7rem;
}

/* Nome do cliente na listagem — ver comentário completo em
   public_html/clientes/index.php (bloco do nome). Livre pra encolher no
   mobile (min-w-0 flex-1 via Tailwind, direto no HTML); a partir de md
   ganha uma largura previsível pra alinhar com a coluna "Comprado" ao
   lado (13rem: já validado nunca estourar entre md-xl, ver comentário no
   HTML); a partir de xl, quando Representante/Marca preferida também
   entram na linha, passa a poder encolher (flex-shrink) em vez de ficar
   travado em 24rem — é a única coluna desta linha que cede espaço; as
   outras (.cliente-coluna-truncada, Comprado, badge+CTA) continuam
   fixas. */
@media (min-width: 768px) {
    .cliente-lista-nome {
        flex: 0 0 13rem;
        width: 13rem;
    }
}

@media (min-width: 1280px) {
    .cliente-lista-nome {
        flex: 1 1 16rem;
        width: 16rem;
        min-width: 8rem;
    }
}

/* Badge de categoria (Ouro/Prata/Diamante/Platina/Partner — ver
   corBadgeCategoria() em lib/apresentacao.php) — forma/tamanho fixados
   aqui, no CSS carregado de forma síncrona (<link rel="stylesheet">), em
   vez de via classes Tailwind (rounded-full/px-2.5/py-1/text-xs). Achado
   nesta sessão (2026-09-17): o Tailwind vem por CDN (Play, sem build step,
   Emenda 1.3.0) e gera essas classes em JS DEPOIS do primeiro paint — numa
   lista longa, uma ou duas linhas às vezes renderizavam antes desse JS
   terminar, ficando visivelmente mais estreitas/menos arredondadas que as
   outras (mesmo com o valor de `categoria` idêntico, confirmado por
   HEX(categoria) direto no banco). `.badge-categoria` cobre TODAS as
   categorias com a mesma geometria — só `.badge-tier-alto` (negrito) muda
   por tier, nunca o tamanho.
   `min-width` + `justify-content: center` (pedido do usuário em
   2026-09-17, depois do fix acima: "DIAMANTE"/8 letras ficava mais largo
   que "PARTNER"/7 mesmo com o mesmo padding — texto maior sempre ocupa
   mais espaço num badge que cresce com o conteúdo) — trava todas no mesmo
   width, largo o bastante pra "DIAMANTE"/"PLATINA" (as mais compridas),
   com o texto centralizado dentro em vez de coladas na borda. */
.badge-categoria {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 5.75rem;
    border-radius: 9999px;
    padding: 0.25rem 0.625rem;
    font-size: 0.75rem;
    line-height: 1.1;
}

.badge-tier-alto {
    font-weight: 800;
    letter-spacing: 0.01em;
}

/* Pódio de "Itens que mais comprou" (pedido do usuário em 2026-09-19) —
   1º/2º/3º ganham cor própria (ouro/prata/bronze, mesmos tons de
   OURO/PRATA de corBadgeCategoria() acima, mais um bronze novo pra
   completar o pódio); 4º a 10º caem todos no mesmo neutro
   (.rank-badge-padrao), de propósito iguais entre si — o contraste é
   "pódio vs. resto do top 10", não uma escada de 10 degraus. */
.rank-badge {
    display: inline-flex;
    height: 1.5rem;
    width: 1.5rem;
    align-items: center;
    justify-content: center;
    border-radius: 9999px;
    font-size: 0.75rem;
    font-weight: 700;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.08);
}

.rank-badge-ouro {
    background: #EFD98A;
    color: #6E5314;
}

.rank-badge-prata {
    background: #C7CDD3;
    color: #4E5860;
}

.rank-badge-bronze {
    background: #E3B080;
    color: #7A431A;
}

.rank-badge-padrao {
    background: var(--ph-neutral-chip-bg);
    color: var(--ph-neutral-chip-text);
}

/* Chip "Top 10" ao lado do título — deixa explícito que a tabela abaixo
   é um recorte (top 10), não a lista completa de itens comprados
   (pedido do usuário em 2026-09-19). */
.rank-top10-chip {
    display: inline-flex;
    align-items: center;
    border-radius: 9999px;
    background: var(--ph-neutral-chip-bg);
    padding: 0.125rem 0.5rem;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: var(--ph-neutral-chip-text);
    text-transform: uppercase;
}

/* Selo de oferta ativa (spec 002-selo-oferta-ativa, ver badgeOferta() em
   lib/apresentacao.php) — cor vem sempre do banco (marketing decide qual é,
   não é derivada do desconto), só a geometria é fixa aqui, mesmo motivo de
   .badge-categoria acima (Tailwind via CDN só aplica classes depois do
   primeiro paint, então geometria em CSS real evita o "pulo" de layout). */
.badge-oferta {
    display: inline-flex;
    align-items: center;
    border-radius: 9999px;
    padding: 0.125rem 0.5rem;
    font-size: 0.6875rem;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: 0.01em;
}

/* Selo "Lançamento" (pedido do usuário em 2026-09-21: destacar produto com
   primeira entrada em estoque no ano corrente — coluna LANCAMENTO do
   "Copiar SQL" de Produtosestoque.xlsx). 3ª versão: layout/cores exatos
   fornecidos pelo usuário (gradiente violeta->azul, ícone de foguete,
   cantos levemente arredondados em vez de pill) — só o pulso contínuo
   (escala + anel de sombra, mesma técnica de .kpi-pulse-azul/violeta acima)
   foi acrescentado por cima, a pedido do usuário ("deixe ele pulsando
   forever"). */
.tag-lancamento {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: -webkit-linear-gradient(left, #7c3aed, #2563eb);
    background: linear-gradient(90deg, #7c3aed, #2563eb);
    color: #ffffff;
    font-family: -apple-system, "Segoe UI", Roboto, sans-serif;
    font-size: 11px;
    font-weight: 500;
    line-height: 1;
    padding: 4px 9px;
    border-radius: 5px;
    white-space: nowrap;
    vertical-align: middle;
    margin-left: 8px;
    animation: tag-lancamento-pulso 1.4s ease-in-out infinite;
}
.tag-lancamento svg {
    flex-shrink: 0;
}

@keyframes tag-lancamento-pulso {
    0%, 100% {
        transform: scale(1);
        box-shadow: 0 0 0 0 rgba(124, 58, 237, 0.6);
    }
    50% {
        transform: scale(1.14);
        box-shadow: 0 0 0 5px rgba(124, 58, 237, 0);
    }
}

@media (prefers-reduced-motion: reduce) {
    .tag-lancamento {
        animation: none;
    }
}

/* ============================================================================
   COMPONENTS: Empty / Error States
   ============================================================================ */

.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    text-align: center;
    padding: 2.5rem 1.5rem;
    border: 1px dashed var(--proinsight-neutral-200);
    border-radius: 0.75rem;
    background: var(--proinsight-neutral-50);
}

.empty-state-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 3rem;
    height: 3rem;
    border-radius: 9999px;
    background: var(--proinsight-white);
    border: 1px solid var(--proinsight-neutral-200);
    color: var(--ph-text-secondary);
    margin-bottom: 0.25rem;
}

.empty-state-title {
    font-size: 0.875rem;
    font-weight: 800;
    color: var(--proinsight-neutral-700);
}

.empty-state-subtitle {
    font-size: 0.8125rem;
    color: var(--ph-text-secondary);
    max-width: 28rem;
}

/* Variante pra linha vazia dentro de tabela (célula única com colspan) —
   mesma linguagem visual do `.empty-state` acima (ícone em círculo + texto),
   mas sem a caixa tracejada/fundo próprios: a tabela já está dentro de um
   `.ph-card` com borda, então uma segunda caixa por dentro seria "caixa
   dentro de caixa" (auditoria sistêmica 2026-09-20). Usada em
   admin/auditoria-detalhe.php, que antes tinha só uma linha de texto solta
   onde toda outra tabela vazia do app usa este padrão de ícone + título. */
.empty-state-row {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 1.5rem 1rem;
}

.empty-state-row .empty-state-icon {
    width: 2.25rem;
    height: 2.25rem;
}

/* ============================================================================
   COMPONENTS: Buttons & Forms
   ============================================================================ */

.btn {
    padding: 0.75rem 1.5rem;
    border-radius: 0.375rem;
    font-family: "Montserrat App", system-ui, sans-serif;
    font-size: 0.8125rem;
    font-weight: 800;
    border: none;
    cursor: pointer;
    transition: all var(--proinsight-transition-normal);
    min-height: 2.75rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

/* Fundo escuro + texto branco, não laranja sólido: branco sobre
   --proinsight-orange dá ~2.66:1, falha AA (mesmo problema medido na
   auditoria pra laranja como cor de texto). Segue o mesmo padrão já
   validado em `.ph-login-submit` — laranja fica só como glow/acento no
   hover e no foco, reservado pra marca/IA, não como preenchimento de botão.
   `#fff` literal, não var(--proinsight-white): essa variável passou a
   significar "fundo de card" desde os 4 temas (2026-09-16) e fica escura
   nos 3 temas não-claro — texto ficaria invisível sobre este fundo também
   escuro (achado nesta issue, testando os temas de verdade). */
.btn-primary {
    background: var(--proinsight-ink);
    color: #fff;
}

.btn-primary:hover:not(:disabled) {
    background: #222222;
    box-shadow: 0 0 0 4px rgba(212, 145, 47, 0.12);
}

.btn-primary:focus-visible {
    outline: 2px solid var(--proinsight-orange);
    outline-offset: 2px;
}

.btn-secondary {
    background: var(--proinsight-white);
    color: var(--proinsight-neutral-900);
    border: 1px solid var(--proinsight-neutral-200);
}

.btn-secondary:hover:not(:disabled) {
    background: var(--proinsight-neutral-50);
    border-color: var(--proinsight-neutral-400);
}

.btn-tertiary {
    background: transparent;
    color: var(--ph-status-info);
    border: 1px solid var(--ph-status-info);
}

.btn-tertiary:hover:not(:disabled) {
    background: rgba(47, 111, 237, 0.05);
}

.btn:disabled {
    background: var(--proinsight-neutral-50);
    color: var(--proinsight-neutral-400);
    cursor: not-allowed;
}

/* Input fields */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="search"],
textarea,
select {
    padding: 0.625rem 0.75rem;
    border: 1px solid var(--proinsight-neutral-200);
    border-radius: 0.375rem;
    font-family: "Montserrat App", system-ui, sans-serif;
    font-size: 0.875rem;
    color: var(--proinsight-neutral-900);
    transition: all var(--proinsight-transition-fast);
    background: var(--proinsight-white);
}

/* Campos de busca com lupa (clientes/index.php, clientes/detalhe.php) — o
   ícone + input já vivem dentro de um container-pílula que dá a própria
   borda/fundo/padding; sem isso, a regra genérica `input[type="search"]`
   acima (especificidade maior que uma classe Tailwind isolada, como
   `border-0`/`bg-transparent`/`py-2` — atributo+tipo sempre vence uma
   classe só) entrava por cima e somava borda + padding DE NOVO por dentro
   do container, espremendo o espaço de texto (achado nesta sessão: o
   placeholder aparecia cortado em "...ou cate" em vez do texto completo).
   `-webkit-appearance`/`appearance: none` também tira o "chrome" nativo de
   campo de busca do Safari/Chrome antigo, que reservava espaço extra à
   direita mesmo sem digitar nada. */
input[type="search"].busca-flush {
    padding: 0;
    border: none;
    background: transparent;
    -webkit-appearance: none;
    appearance: none;
}

input:focus,
textarea:focus,
select:focus {
    outline: none;
    border-color: var(--ph-focus);
    box-shadow: 0 0 0 3px rgba(47, 111, 237, 0.18);
}

input:disabled,
textarea:disabled,
select:disabled {
    background: var(--proinsight-neutral-50);
    color: var(--proinsight-neutral-400);
    cursor: not-allowed;
}

/* Chips & Tags */
.chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.375rem 0.75rem;
    border-radius: 9999px;
    font-size: 0.75rem;
    font-weight: 800;
    border: 1px solid;
}

.chip-blue {
    background: rgba(59, 130, 246, 0.1);
    border-color: var(--proinsight-blue);
    color: var(--proinsight-blue);
}

.chip-violet {
    background: rgba(139, 92, 246, 0.1);
    border-color: var(--proinsight-violet);
    color: var(--proinsight-violet);
}

.chip-emerald {
    background: rgba(16, 185, 129, 0.1);
    border-color: var(--proinsight-emerald);
    color: var(--proinsight-emerald);
}

.chip-cyan {
    background: rgba(6, 182, 212, 0.1);
    border-color: var(--proinsight-cyan);
    color: var(--proinsight-cyan);
}

.chip-pink {
    background: rgba(236, 72, 153, 0.1);
    border-color: var(--proinsight-pink);
    color: var(--proinsight-pink);
}

.chip-orange {
    background: rgba(212, 145, 47, 0.1);
    border-color: var(--proinsight-orange);
    color: var(--ph-brand-text);
}

.chip-danger {
    background: rgba(180, 35, 24, 0.08);
    border-color: var(--ph-status-danger);
    color: var(--ph-status-danger);
}

/* Origem da linha no pedido sugerido (Reposição/Novo), embaixo do código
   (issue #198: o .chip antes da descrição pesava mais que o nome do produto
   e empilhava com Lançamento/alto estoque/oferta). Rótulo discreto, sem
   borda: a cor fica só no ponto e o texto usa neutro tematizado, porque
   azul/violeta puros em texto de 10px não passam contraste AA no tema
   claro — e o significado não depende só da cor. */
.ph-origem-pedido {
    display: flex;
    align-items: center;
    gap: 0.3125rem;
    margin-top: 0.1875rem;
    font-size: 0.625rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--tw-neutral-600);
}

.ph-origem-pedido::before {
    content: "";
    width: 0.4375rem;
    height: 0.4375rem;
    flex-shrink: 0;
    border-radius: 9999px;
    background: currentColor;
}

.ph-origem-pedido-reposicao::before {
    background: var(--proinsight-blue);
}

.ph-origem-pedido-novo::before {
    background: var(--proinsight-violet);
}

/* ============================================================================
   COMPONENTS: Alerts & Status Messages
   ============================================================================ */

.alert {
    padding: 0.75rem 1rem;
    border-left: 4px solid;
    border-radius: 0.25rem;
    font-size: 0.8125rem;
    line-height: 1.5;
}

.alert-info {
    background: rgba(47, 111, 237, 0.1);
    border-color: var(--ph-status-info);
    color: var(--proinsight-neutral-900);
}

.alert-success {
    background: var(--ph-status-success-surface);
    border-color: var(--ph-status-success);
    color: var(--proinsight-neutral-900);
}

.alert-warning {
    background: rgba(236, 72, 153, 0.1);
    border-color: var(--proinsight-pink);
    color: var(--proinsight-neutral-900);
}

.alert-danger {
    background: var(--ph-status-danger-surface);
    border-color: var(--ph-status-danger);
    color: var(--proinsight-neutral-900);
}

/* Variante compacta (resumo do pedido, cards estreitos) — classe dedicada
   em vez de sobrescrever via utilitário Tailwind: o Tailwind via CDN é
   injetado ANTES de app.css no <head> (lib/layout.php), então uma classe
   Tailwind isolada perde de qualquer regra de app.css com a mesma
   especificidade, não importa a ordem das classes no HTML (mesmo problema
   já documentado em `.badge-categoria` acima). */
.alert-compact {
    padding: 0.5rem 0.75rem;
}

/* ============================================================================
   COMPONENTS: Loading & Motion
   ============================================================================ */

.loading-overlay {
    position: fixed;
    inset: 0;
    display: none;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.7);
    z-index: var(--z-overlay);
}

.loading-overlay.is-visible {
    display: flex;
}

.loading-spinner {
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    border: 3px solid var(--proinsight-neutral-200);
    border-top-color: var(--proinsight-neutral-900);
    animation: proinsight-spin 0.7s linear infinite;
}

@keyframes proinsight-spin {
    to {
        transform: rotate(360deg);
    }
}

@media (prefers-reduced-motion: reduce) {
    .loading-spinner {
        animation: none;
    }
}

/* ============================================================================
   COMPONENTS: Shell — sidebar (drawer mobile)
   ============================================================================ */

/* Bug real reportado em dispositivo (Xiaomi Redmi Note 13, Chrome for
   Android, 2026-09-20): o Tailwind `h-screen` (lib/layout.php) vira
   `height: 100vh`, e no Chrome mobile o `100vh` mede a viewport GRANDE (com
   a barra de endereço recolhida) — maior que a área realmente visível
   quando a barra ainda está à mostra (o estado inicial mais comum). Como
   `#ph-sidebar` é `position: fixed` (`inset-y-0`), o próprio drawer nasce
   mais alto que a tela visível, cortando o rodapé (tema/trocar senha/Sair)
   pra baixo da dobra — e como o CONTEÚDO cabe dentro de `100vh`, o
   `overflow-y-auto` do próprio elemento não tem o que rolar (não é o
   conteúdo que estoura a caixa, é a caixa que nasce maior que a tela).
   Sobrescrito aqui por especificidade de id (mais alta que a utility class
   do Tailwind, ver nota sobre ordem de injeção logo no topo deste arquivo)
   com `100dvh`, que acompanha a viewport realmente visível; `100vh` como
   fallback pra navegadores/WebViews sem suporte a `dvh`. */
#ph-sidebar {
    height: 100vh;
    height: 100dvh;
}

/* ============================================================================
   COMPONENTS: Data Tables
   ============================================================================ */

.data-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--proinsight-white);
    border: 1px solid var(--proinsight-neutral-200);
    border-radius: 0.5rem;
    overflow: hidden;
}

.data-table thead {
    background: var(--proinsight-neutral-50);
    border-bottom: 1px solid var(--proinsight-neutral-200);
}

.data-table th {
    padding: 0.75rem 1rem;
    text-align: left;
    font-size: 0.6875rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.025em;
    color: var(--proinsight-neutral-700);
}

.data-table td {
    padding: 0.75rem 1rem;
    font-size: 0.8125rem;
    color: var(--proinsight-neutral-900);
    border-bottom: 1px solid var(--proinsight-neutral-200);
}

.data-table tbody tr:hover {
    background: var(--proinsight-neutral-50);
}

.data-table tbody tr:last-child td {
    border-bottom: none;
}

/* Right-align numbers */
.data-table td.numeric {
    text-align: right;
    font-weight: 800;
}

/* ============================================================================
   UTILITIES & ACCESSIBILITY
   ============================================================================ */

/* Achado nesta sessão (2026-09-17, editor inline de meta/supermeta em
   clientes/detalhe.php): um elemento com o atributo `hidden` E uma classe
   Tailwind de `display` (`flex`/`grid`/`block`...) NÃO fica escondido de
   verdade — `[hidden] { display: none }` é regra da folha de estilo padrão
   do navegador (UA stylesheet), e QUALQUER regra de autor (inclusive as que
   o Tailwind injeta via CDN) vence uma regra de UA, não importa
   especificidade nem ordem. `!important` aqui é proposital e o único jeito
   confiável de garantir que `hidden` sempre esconda de verdade, mesmo
   combinado com `flex`/`grid`/etc. — sem isso, o padrão (usado em vários
   lugares do app: toggle de detalhes de sugestão, formulários, overlays)
   quebra silenciosamente sempre que alguém junta `hidden` com uma classe de
   display do Tailwind no mesmo elemento. */
[hidden] {
    display: none !important;
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border-width: 0;
}

.focus-visible-ring:focus-visible {
    outline: 2px solid var(--ph-focus);
    outline-offset: 2px;
}

/* ============================================================================
   LAYOUT: Responsive Grid & Flex Utilities
   ============================================================================ */

.grid-auto {
    display: grid;
    gap: 1rem;
    grid-auto-flow: dense;
}

.flex-center {
    display: flex;
    align-items: center;
    justify-content: center;
}

.flex-between {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

/* ============================================================================
   TYPOGRAPHY: Utilities
   ============================================================================ */

.text-brand {
    color: var(--ph-brand-text);
}

.text-blue {
    color: var(--proinsight-blue);
}

.text-violet {
    color: var(--proinsight-violet);
}

.text-emerald {
    color: var(--proinsight-emerald);
}

.text-cyan {
    color: var(--proinsight-cyan);
}

.text-pink {
    color: var(--proinsight-pink);
}

.text-muted {
    color: var(--ph-text-secondary);
}

/* Alias do token semântico novo pra uso direto em markup (mesmo espírito
   de `.text-muted`/`.text-brand` acima) — usado pra substituir a classe
   utilitária `text-neutral-400` do Tailwind (mapeada em --tw-neutral-400,
   #a3a3a3) onde ela colore TEXTO/ícone informativo real: ~2.5:1 sobre
   branco, falha AA (auditoria 02). --tw-neutral-400 continua existindo
   pra uso não-textual (borda, placeholder, estado disabled — que a WCAG
   não exige em contraste). */
.text-ph-secondary {
    color: var(--ph-text-secondary);
}

.text-sm {
    font-size: 0.75rem;
}

.text-xs {
    font-size: 0.6875rem;
}

.font-medium {
    font-weight: 400;
}

/* As 3 classes abaixo coexistem porque templates diferentes já usavam nomes
   diferentes pro mesmo peso (só 400/800 são carregados via @font-face no
   topo do arquivo) — mantidas por compatibilidade com os templates, mas
   apontando pro mesmo valor num único lugar em vez de 3 declarações soltas
   que podem divergir no futuro. */
.font-semibold,
.font-bold,
.font-extra-bold {
    font-weight: 800;
}

/* ============================================================================
   COMPONENTS: Charts & Data Visualization
   ============================================================================ */

.chart-wrap {
    width: 100%;
}

.chart-point {
    cursor: pointer;
}

/* `outline: none` some ao ponto de foco padrão do navegador é um retângulo
   sobre um <circle> de SVG — visualmente quebrado. `:focus-visible` (não
   `:focus`) pra só suprimir em navegação por teclado real, nunca em clique
   de mouse. O substituto visível vem do stroke colorido logo abaixo, não
   fica sem indicador nenhum. */
.chart-point:focus-visible {
    outline: none;
}

.chart-point-dot {
    fill: #2563eb;
    stroke: var(--proinsight-white);
}

.chart-point:focus .chart-point-dot,
.chart-point.is-hover .chart-point-dot {
    r: 6;
    fill: var(--proinsight-blue);
}

.chart-point:focus-visible .chart-point-dot {
    stroke: var(--ph-focus);
    stroke-width: 2px;
}

.chart-line-glow {
    filter: drop-shadow(0 2px 3px rgba(59, 130, 246, 0.25));
}

/* Animação de entrada dos gráficos de "Compras por mês" (pedido do usuário
   em 2026-09-20: números dos cards e gráfico devem "partir do valor mais
   baixo" e crescer até o valor real ao carregar a tela) — cresce a partir da
   base do gráfico via `scaleY`, não um fade/zoom central; `transform-origin`
   é fixado inline por lib/chart.php (na altura de $baseY, a linha de base do
   eixo X) porque esse valor é calculado em PHP a partir das dimensões do
   SVG. app.js adiciona ".is-animado" (via requestAnimationFrame, depois de
   forçar um reflow) pra disparar a transição — sem isso o navegador poderia
   pular direto pro estado final sem transicionar. Só a geometria de dado
   (área/linha/pontos) fica dentro do grupo; texto de eixo é renderizado FORA
   dele (mesmo arquivo) pra não espichar/borrar sob o scaleY não-uniforme. */
.chart-serie-grupo {
    transform: scaleY(0);
    transition: transform 1000ms var(--proinsight-ease-out);
}

.chart-serie-grupo.is-animado {
    transform: scaleY(1);
}

@media (prefers-reduced-motion: reduce) {
    .chart-serie-grupo {
        transition: none;
        transform: scaleY(1);
    }
}

/* Elementos estruturais do gráfico (grade, rótulos de eixo, linha de média)
   — cor via variável pra acompanhar o tema (pedido do usuário em
   2026-09-16), diferente das cores de dado (azul da série, cores por marca
   em corMarca()) que ficam fixas nos 4 temas de propósito. */
.chart-grid-linha {
    stroke: var(--chart-grid);
}

.chart-eixo-label {
    fill: var(--chart-muted);
}

.chart-media-linha {
    stroke: var(--chart-muted);
}

.chart-media-label {
    fill: var(--chart-muted-forte);
}

/* ============================================================================
   COMPONENTS: Theme Picker (pedido do usuário em 2026-09-16)
   ============================================================================ */

.ph-tema-menu {
    position: absolute;
    right: 0;
    z-index: var(--z-dropdown);
    display: none;
    min-width: 13rem;
    border-radius: var(--radius-xl);
    border: 1px solid var(--proinsight-neutral-200);
    background: var(--proinsight-white);
    box-shadow: var(--shadow-lg);
    padding: 0.375rem;
}

.ph-tema-menu.is-aberto {
    display: block;
}

.ph-tema-menu-baixo {
    top: calc(100% + 0.5rem);
}

.ph-tema-menu-cima {
    bottom: calc(100% + 0.5rem);
}

.ph-tema-opcao {
    display: flex;
    width: 100%;
    align-items: center;
    gap: 0.625rem;
    border: none;
    border-radius: 0.5rem;
    background: transparent;
    padding: 0.5rem 0.625rem;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--proinsight-neutral-700);
    cursor: pointer;
    text-align: left;
    transition: background-color var(--proinsight-transition-fast);
}

.ph-tema-opcao:hover {
    background: var(--proinsight-neutral-50);
}

.ph-tema-opcao:focus-visible {
    outline: 2px solid var(--ph-focus);
    outline-offset: -2px;
}

.ph-tema-amostra {
    height: 1rem;
    width: 1rem;
    flex-shrink: 0;
    border-radius: 9999px;
    border: 1px solid rgba(0, 0, 0, 0.12);
}

.ph-tema-check {
    margin-left: auto;
    display: flex;
    color: var(--ph-brand-text);
    opacity: 0;
}

.ph-tema-opcao[aria-checked="true"] .ph-tema-check {
    opacity: 1;
}

.chart-bar {
    transition: fill var(--proinsight-transition-fast);
}

.chart-bar:hover {
    opacity: 0.8;
}

/* ============================================================================
   COMPONENTS: Product Images & Lightbox
   ============================================================================ */

/* Moldura visível (pedido do usuário em 2026-09-19: "algumas imagens
   ficaram apenas com um traço vertical") — a maioria das fotos de produto
   tem fundo branco/quase branco (fotografia de catálogo), então um
   thumbnail de 36px com só 1px de borda clara (border-neutral-200) contra o
   fundo branco da própria tabela ficava, na prática, quase invisível: só as
   bordas esquerda/direita sobravam visíveis, lidas como "um traço vertical"
   em vez de um quadrado clicável. Padding + fundo neutro aqui no botão (não
   na <img>, que é opaca e cobriria qualquer fundo posto nela) cria uma
   "cercadura" cinza sempre visível por trás da foto, com contraste
   garantido independente da cor do produto fotografado. */
.foto-produto-botao {
    display: block;
    cursor: zoom-in;
    padding: 0.1875rem;
    border-radius: 0.625rem;
    background: var(--proinsight-neutral-50);
    border: 1px solid var(--proinsight-neutral-200);
    transition: transform var(--proinsight-transition-fast),
                box-shadow var(--proinsight-transition-fast),
                border-color var(--proinsight-transition-fast);
}

.foto-produto-botao img {
    display: block;
    border-radius: 0.375rem;
}

.foto-produto-botao:hover {
    transform: scale(1.02);
    border-color: var(--proinsight-neutral-400);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
}

.foto-produto-botao:focus-visible {
    outline: 2px solid var(--proinsight-neutral-900);
    outline-offset: 2px;
}

.ph-lightbox {
    position: fixed;
    inset: 0;
    z-index: var(--z-modal);
    display: none;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
    background: rgba(23, 23, 23, 0.75);
}

.ph-lightbox.is-visible {
    display: flex;
}

.ph-lightbox-figura {
    max-width: min(90vw, 640px);
    max-height: 85vh;
    margin: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
}

.ph-lightbox-figura img {
    max-width: 100%;
    max-height: 70vh;
    border-radius: 0.75rem;
    background: #fff;
    box-shadow: 0 24px 48px rgba(0, 0, 0, 0.35);
}

.ph-lightbox-legenda {
    color: #f5f5f5;
    font-size: 0.8125rem;
    text-align: center;
}

.ph-lightbox-fechar {
    position: absolute;
    top: 1rem;
    right: 1rem;
    display: flex;
    align-items: center;
    justify-content: center;
    /* 2.75rem/44px — alvo de toque mínimo (auditoria sistêmica 2026-09-20),
       antes 2.25rem. Botão isolado no canto do overlay, sem vizinho por
       perto, então crescer não arrisca sobrepor outro elemento. */
    height: 2.75rem;
    width: 2.75rem;
    border-radius: 9999px;
    border: none;
    background: rgba(255, 255, 255, 0.12);
    color: #fff;
    cursor: pointer;
}

.ph-lightbox-fechar:hover {
    background: rgba(255, 255, 255, 0.22);
}

/* Tutorial de boas-vindas (pedido do usuário em 2026-09-15) — overlay sobre
   a tela de clientes logo após o login, fundo borrado em vez de escurecido
   sólido (como o .ph-lightbox) pra deixar a tela principal ainda visível
   por trás, reforçando que é "sobre" o app de verdade, não uma página nova. */
.ph-tutorial-overlay {
    position: fixed;
    inset: 0;
    z-index: var(--z-modal-top);
    display: none;
    align-items: center;
    justify-content: center;
    padding: 1.25rem;
    background: rgba(23, 23, 23, 0.35);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

.ph-tutorial-overlay.is-visible {
    display: flex;
}

.ph-tutorial-card {
    position: relative;
    width: 100%;
    max-width: 30rem;
    max-height: 90vh;
    overflow-y: auto;
    border-radius: 0.75rem;
    background: var(--proinsight-white);
    padding: 1.75rem;
    box-shadow: 0 24px 48px rgba(0, 0, 0, 0.25);
}

/* Variante mais larga do mesmo overlay/card acima — pedido do usuário em
   2026-09-18: tutorial de "como colar no Mercanet" (público diferente do
   de boas-vindas: sob demanda, via lâmpada na seção de Sugestões de
   venda, não automático no login) precisa de espaço pra passo a passo com
   screenshot em cada passo, o que não cabe nos 30rem do card padrão. */
.ph-tutorial-card-larga {
    max-width: 42rem;
}

.ph-tutorial-passo-numero {
    display: flex;
    height: 1.75rem;
    width: 1.75rem;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    border-radius: 9999px;
    background: var(--proinsight-orange);
    color: var(--proinsight-white);
    font-size: 0.8125rem;
    font-weight: 800;
}

.ph-tutorial-passo-imagem {
    display: block;
    width: 100%;
    border-radius: 0.5rem;
    border: 1px solid var(--proinsight-neutral-200);
    margin-top: 0.625rem;
}

.ph-tutorial-fechar {
    position: absolute;
    /* 0.5rem, não 0.875rem — o botão cresceu (ver comentário abaixo) e
       precisa ficar mais perto do canto de verdade pra não invadir o título
       do card, que começa no padding-top de `.ph-tutorial-card` (1.75rem). */
    top: 0.5rem;
    right: 0.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    /* 2.75rem/44px — alvo de toque mínimo (auditoria sistêmica 2026-09-20),
       antes 2rem. */
    height: 2.75rem;
    width: 2.75rem;
    border-radius: 9999px;
    border: none;
    background: var(--proinsight-neutral-50);
    color: var(--ph-text-secondary);
    cursor: pointer;
    font-size: 1.125rem;
    line-height: 1;
}

.ph-tutorial-fechar:hover {
    background: var(--proinsight-neutral-200);
    color: var(--proinsight-neutral-700);
}

.ph-tutorial-icone {
    display: flex;
    height: 2.25rem;
    width: 2.25rem;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    border-radius: 9999px;
    border: 1px solid;
}

.ph-tutorial-icone-blue {
    background: rgba(59, 130, 246, 0.1);
    border-color: var(--proinsight-blue);
    color: var(--proinsight-blue);
}

.ph-tutorial-icone-violet {
    background: rgba(139, 92, 246, 0.1);
    border-color: var(--proinsight-violet);
    color: var(--proinsight-violet);
}

.ph-tutorial-icone-pink {
    background: rgba(236, 72, 153, 0.1);
    border-color: var(--proinsight-pink);
    color: var(--proinsight-pink);
}

.ph-tutorial-icone-emerald {
    background: rgba(16, 185, 129, 0.1);
    border-color: var(--proinsight-emerald);
    color: var(--proinsight-emerald);
}

/* Bullet de "Sugestões com IA" no tutorial (pedido do usuário em
   2026-09-17) — laranja da marca, não uma das 4 cores semânticas acima, pra
   marcar que é a mesma identidade de IA do badge/estrela do login, não mais
   um KPI/dado qualquer do dashboard. */
.ph-tutorial-icone-orange {
    background: rgba(212, 145, 47, 0.12);
    border-color: var(--proinsight-orange);
    color: var(--ph-brand-text);
}

/* Variante de perigo (diálogo de confirmação de exclusão/reset de senha,
   admin/representantes.php) — vermelho semântico, nunca laranja, pra não
   confundir "perigo" com a identidade de marca/IA. */
.ph-tutorial-icone-danger {
    background: var(--ph-status-danger-surface);
    border-color: var(--ph-status-danger);
    color: var(--ph-status-danger);
}

/* Overlay de progresso da importação principal (pedido do usuário em
   2026-09-21, ver #ph-importando-overlay em admin/importar-dados.php) —
   reaproveita o shell .ph-tutorial-card (blur + card + sombra), só ganha
   entrada animada (nenhum outro overlay do app tem — .ph-login-card é a
   única outra "entrada de card" que existe hoje) e uma barra de progresso
   simulada (sem % real: é um único POST síncrono, sem retorno incremental
   do servidor). */
.ph-importando-card {
    max-width: 24rem;
    text-align: center;
    animation: ph-login-fade-in 400ms var(--proinsight-ease-out) both;
}

.ph-importando-bar {
    height: 0.5rem;
    margin-top: 1.5rem;
    background: var(--proinsight-neutral-200);
    border-radius: 9999px;
    overflow: hidden;
}

.ph-importando-bar-fill {
    height: 100%;
    width: 0%;
    border-radius: 9999px;
    background-image: linear-gradient(90deg, #D4912F, #F6C76C, #D4912F);
    background-size: 200% auto;
    transition: width 400ms linear;
    animation: ph-ia-shimmer 1.6s ease-in-out infinite;
}

.ph-importando-etapa {
    margin-top: 0.75rem;
    font-size: 0.8125rem;
    color: var(--ph-text-secondary);
}

@media (prefers-reduced-motion: reduce) {
    .ph-importando-card {
        animation: none;
    }
    .ph-importando-bar-fill {
        animation: none;
    }
}

.chart-tooltip {
    position: fixed;
    transform: translate(-50%, calc(-100% - 8px));
    display: none;
    pointer-events: none;
    background: #171717;
    color: #fff;
    font-size: 0.75rem;
    padding: 0.375rem 0.625rem;
    border-radius: 0.375rem;
    white-space: nowrap;
    z-index: var(--z-tooltip);
}

.chart-tooltip strong {
    font-weight: 800;
}

.chart-tooltip.is-visible {
    display: block;
}

/* Aviso de "só top 3 visíveis por padrão" (pedido do usuário em 2026-09-17)
   acima da legenda do gráfico de compras por mês por marca. */
.chart-marca-explicacao {
    margin-top: 0.75rem;
    font-size: 0.75rem;
    color: var(--ph-text-secondary);
}

/* Legenda do gráfico de compras por mês por marca (lib/chart.php,
   renderizarGraficoComprasPorMesMarca()) — pill design (mesma linguagem dos
   .chip do resto do app), redesenhado em 2026-09-19 (estava cru: texto solto
   sem estrutura de botão). Cor por marca é gerada em HSL arbitrário (não são
   os 5 tons fixos do resto do app), por isso cada <button> recebe a cor via
   custom property inline (--marca-cor), usada aqui pra borda/fundo tingidos
   com color-mix — só a bolinha (.chart-legenda-cor) mantém o fill sólido
   inline por simplicidade (já vinha assim). */
.chart-legenda-marcas {
    margin-top: 0.75rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/* .chart-legenda-item é um <button> (filtro por marca, pedido do usuário em
   2026-09-15) — pill com borda tingida na cor da marca quando visível
   (sinaliza "ativa" sem depender só da opacidade) e recolhida/neutra quando
   escondida. */
.chart-legenda-item {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    border: 1px solid color-mix(in srgb, var(--marca-cor) 40%, var(--ph-border));
    background: color-mix(in srgb, var(--marca-cor) 8%, var(--proinsight-neutral-50));
    padding: 0.3125rem 0.625rem;
    border-radius: 9999px;
    font-family: inherit;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--proinsight-neutral-700);
    cursor: pointer;
    transition: opacity var(--proinsight-transition-fast),
                background var(--proinsight-transition-fast),
                border-color var(--proinsight-transition-fast),
                transform var(--proinsight-transition-fast);
}

.chart-legenda-item:hover {
    background: color-mix(in srgb, var(--marca-cor) 16%, var(--proinsight-neutral-50));
    transform: translateY(-1px);
}

.chart-legenda-item:focus-visible {
    outline: 2px solid var(--ph-focus);
    outline-offset: 2px;
}

/* Marca "escondida" (clicada pra filtrar fora) — borda tracejada e neutra,
   sem o tingimento de cor, pra ficar claro visualmente que está fora do
   gráfico (mas a bolinha mantém a cor, pra reconhecer qual marca é). */
.chart-legenda-item.is-oculta {
    background: transparent;
    border-style: dashed;
    border-color: var(--ph-border);
    color: var(--proinsight-neutral-400);
    opacity: 0.7;
}

.chart-legenda-item.is-oculta:hover {
    background: var(--proinsight-neutral-50);
    transform: none;
}

.chart-legenda-cor {
    height: 0.5rem;
    width: 0.5rem;
    flex-shrink: 0;
    border-radius: 9999px;
}

.chart-legenda-item.is-oculta .chart-legenda-cor {
    opacity: 0.5;
}

/* Valor total vendido por marca, ao lado do nome na legenda (pedido do
   usuário em 2026-09-15) — o "title" no .chart-legenda-item (tooltip
   nativo, sem JS) já deixa explícito que é a janela de 12 meses; aqui é só
   o número curto, igual ao eixo do gráfico, num tom mais fraco pra separar
   visualmente do nome da marca. */
.chart-legenda-total {
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: var(--proinsight-neutral-400);
}

/* "Mostrar todas" / "Ocultar todas" — movidos pro canto superior direito da
   seção (pedido do usuário em 2026-09-19: "deve ficar posicionado no canto
   superior direito dessa seção"), junto do título (ver
   renderizarBotoesLegendaMarca() em lib/chart.php e o cabeçalho flex em
   detalhe.php); antes ficavam soltos abaixo da legenda. */
.chart-legenda-acoes {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 0;
}

/* Pill outline (em vez de link sublinhado, redesenhado em 2026-09-19) pra
   parecer uma ação de verdade, não só texto. */
.chart-legenda-reset,
.chart-legenda-ocultar {
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--ph-border);
    background: none;
    padding: 0.3125rem 0.75rem;
    border-radius: 9999px;
    font-family: inherit;
    font-size: 0.75rem;
    font-weight: 700;
    cursor: pointer;
    transition: background var(--proinsight-transition-fast),
                border-color var(--proinsight-transition-fast);
}

.chart-legenda-reset {
    color: var(--proinsight-blue);
}

.chart-legenda-reset:hover {
    background: rgba(59, 130, 246, 0.1);
    border-color: var(--proinsight-blue);
}

/* "Ocultar todas" é neutro (não uma cor de marca) — ação secundária/menos
   usada que "Mostrar todas", não precisa do mesmo peso visual. */
.chart-legenda-ocultar {
    color: var(--proinsight-neutral-700);
}

.chart-legenda-ocultar:hover {
    background: var(--proinsight-neutral-50);
    border-color: var(--proinsight-neutral-400);
}

.chart-legenda-reset:focus-visible,
.chart-legenda-ocultar:focus-visible {
    outline: 2px solid var(--ph-focus);
    outline-offset: 2px;
}

/* Abas "Compras por mês" / "Por marca" dentro da seção unificada de
   histórico de compras (fusão de duas <section> pedida pelo usuário em
   2026-09-19 — ver public_html/clientes/detalhe.php). Segmented control:
   trilho neutro com abas pill, mesma linguagem visual de
   .chart-legenda-reset/.chart-legenda-ocultar acima (borda 1px var(--ph-border),
   pill 9999px, foco visível azul). */
.chart-tabs {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.25rem;
    border: 1px solid var(--ph-border);
    border-radius: 9999px;
    background: var(--proinsight-neutral-50);
}

.chart-tab {
    display: inline-flex;
    align-items: center;
    border: 1px solid transparent;
    background: none;
    padding: 0.375rem 0.875rem;
    border-radius: 9999px;
    font-family: inherit;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--proinsight-neutral-500);
    cursor: pointer;
    transition: background var(--proinsight-transition-fast),
                color var(--proinsight-transition-fast),
                border-color var(--proinsight-transition-fast);
}

.chart-tab:hover {
    color: var(--proinsight-neutral-700);
}

/* Aba ativa: pill branca destacada sobre o trilho neutro, com borda e texto
   tingidos de azul — mesmo par de cores que .chart-legenda-reset usa pra
   "ação primária", reforçando "isto está selecionado". */
.chart-tab.is-ativa {
    background: var(--proinsight-white);
    border-color: var(--ph-border);
    color: var(--proinsight-blue);
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06);
}

.chart-tab:focus-visible {
    outline: 2px solid var(--ph-focus);
    outline-offset: 2px;
}

/* Cabeçalho de coluna ordenável — "Todos os produtos comprados"/"Itens que
   mais comprou"/"Último pedido" em clientes/detalhe.php (pedido do usuário
   em 2026-09-20: ordenar crescente/decrescente ao clicar no título da
   coluna). Herda alinhamento/tipografia do <th> pai (uppercase, tracking,
   cor neutra) e só acrescenta o ícone de seta; `.th-ordenar-fim` inverte pro
   lado direito nas colunas numéricas (Qtde./Total/Preço), que já são
   `text-right`. */
.th-ordenar {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    color: inherit;
    text-decoration: none;
    cursor: pointer;
}

.th-ordenar-fim {
    flex-direction: row-reverse;
}

.th-ordenar:hover,
.th-ordenar:focus-visible {
    color: var(--proinsight-neutral-900);
}

.th-ordenar.is-ativa {
    color: var(--proinsight-blue);
}

.th-ordenar:focus-visible {
    outline: 2px solid var(--ph-focus);
    outline-offset: 2px;
    border-radius: 4px;
}

.th-ordenar-icone {
    display: inline-flex;
    opacity: 0.45;
}

.th-ordenar:hover .th-ordenar-icone {
    opacity: 0.75;
}

.th-ordenar-icone.is-ativa {
    opacity: 1;
}

/* Reaproveita o ícone 'chevron-direita' (aponta pra direita) girado, em vez
   de desenhar mais 2 ícones só pra "seta pra cima"/"seta pra baixo" —
   mesmo espírito de reuso de corMarca() nesta tela. */
.th-ordenar-asc {
    transform: rotate(-90deg);
}

.th-ordenar-desc {
    transform: rotate(90deg);
}

/* Botão-lâmpada que revela o motivo da sugestão (public_html/clientes/detalhe.php,
   seção "Sugestões de venda" — pedido do usuário em 2026-09-15: esconder a
   justificativa por padrão, mostrar num clique). "Acesa" (.is-ativa,
   alternada por app.js) usa a mesma cor âmbar do resto do app pra estado
   "pendente"/destaque (ver .badge dourado em outras telas), reforçando a
   metáfora de lâmpada ligada. */
/* ============================================================================
   COMPONENTS: Sugestão de pedido com IA (grid 3:1 + faixa Motivo/Evidência/
   Recência) — redesign visual aprovado, pacote proinsight-claude-handoff/,
   arquivo 07-direcao-visual-imagem-2.md. Motivo/Evidência/Recência ficam
   ocultos por padrão desde 2026-09-19 (pedido do usuário: "sinalizar pra
   clicar pra expandir"), atrás de `.ph-sugestao-motivo-toggle` (JS de
   toggle em app.js) — revisa a versão anterior, que deixava tudo sempre
   visível seguindo a auditoria 02-auditoria-ux-ui-a11y.md ("informação
   explícita, não tooltip"); aqui o toggle tem rótulo de texto sempre
   visível avisando que dá pra expandir, então não é o tooltip que a
   auditoria mirava.
   ============================================================================ */

/* Congelado no topo da viewport (pedido do usuário em 2026-09-20) — a
   tabela de sugestões abaixo pode ter muitas linhas, então o título + selo
   "Powered by AI" ficam sempre visíveis enquanto o resto da seção rola por
   baixo. `margin` negativo do tamanho do padding de `.ph-hero-section`
   (1.5rem) + `padding`/`background`/`border-radius` próprios fazem o fundo
   "sangrar" até a borda do card ao descolar — sem isso ficaria texto sem
   fundo sólido flutuando sobre a tabela. `.ph-resumo-pedido` (mais abaixo,
   já sticky) tem um `top` maior que o de costume pra não ficar por baixo
   deste cabeçalho quando os dois estão grudados ao mesmo tempo. */
.ph-ia-cabecalho {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.75rem;
    position: sticky;
    top: 0;
    z-index: var(--z-sticky);
    margin: -1.5rem -1.5rem 0;
    padding: 1.25rem 1.5rem;
    background: var(--proinsight-white);
    border-bottom: 1px solid var(--proinsight-neutral-200);
    border-radius: 0.5rem 0.5rem 0 0;
}

/* Ações do cabeçalho da IA (Exportar PDF, Compartilhar, selo). Issue #208:
   o bloco era `shrink-0` e nunca quebrava — no celular media 439 px e a
   PÁGINA INTEIRA rolava para o lado (456 px numa tela de 390), o que também
   descentralizava todo overlay `position: fixed` (PDF, Compartilhar,
   tutorial do Mercanet). */
.ph-ia-acoes {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 0.5rem;
    min-width: 0;
    max-width: 100%;
}

@media (max-width: 639px) {
    /* Linha inteira embaixo do título, os dois botões dividindo a largura;
       o selo "Powered by AI" é decorativo e sai para caberem. */
    .ph-ia-acoes {
        flex: 1 1 100%;
        justify-content: flex-start;
    }

    .ph-ia-acoes .ph-ia-acao {
        flex: 1 1 0;
        justify-content: center;
        min-width: 0;
    }

    .ph-ia-acoes .ph-ia-selo {
        display: none;
    }
}

@media (max-width: 1023px) {
    /* Issue #208: grudado no topo, o cabeçalho (título + texto + botões)
       tomava ~21% da tela do celular durante toda a rolagem de um pedido de
       até 65 itens (supermeta, Issue #194). Sticky só no desktop, onde a
       coluna do resumo acompanha ao lado. */
    .ph-ia-cabecalho {
        position: static;
    }
}

.ph-ia-grid {
    display: grid;
    gap: 1.5rem;
    grid-template-columns: 1fr;
}

@media (min-width: 1024px) {
    .ph-ia-grid {
        /* ~3:1, conforme a referência aprovada. minmax(0, ...), não só
           "3fr 1fr" — item de grid tem min-width:auto implícito (mesmo
           problema clássico do flexbox), então sem isso a coluna da tabela
           nunca encolhe abaixo do conteúdo (tabela com várias colunas
           nowrap) e a PÁGINA INTEIRA estoura em vez do scroll horizontal
           interno (.overflow-x-auto) assumir — bug real encontrado via
           Playwright em 1024-1280px (auditoria de mobile/tablet 2026-09-20,
           mascarado em 1440px+ por sobrar espaço de sobra). */
        grid-template-columns: minmax(0, 3fr) minmax(0, 1fr);
        align-items: start;
    }
}

/* Destaque visual próprio (pedido do usuário em 2026-09-19: "destaque com
   outra cor de fundo, borda e cores") — até aqui era um `.ph-card` igual a
   qualquer outro, sem se diferenciar da tabela de sugestões ao lado, apesar
   de ser o resumo/CTA final do pedido. Tingimento em laranja da marca (mesma
   técnica com camada opaca de `var(--proinsight-white)` por baixo usada nos
   cards de Meta/Supermeta, pra funcionar nos 4 temas) + borda na mesma cor.
   `border-color` sozinho (não `border` inteiro) só troca a cor, mantendo
   largura/estilo que `.ph-card` já define — precisa vir DEPOIS de `.ph-card`
   no arquivo pra vencer a cascata (mesma especificidade, ordem decide). */
@media (max-width: 1023px) {
    /* Issue #208: com uma coluna só, o resumo (total, crédito, Mercanet)
       ficava DEPOIS da tabela — 14 telas abaixo num pedido de 65 itens.
       No celular ele vem antes; no desktop continua na coluna ao lado.
       Sem sticky aqui: como primeiro item do grid, ele grudaria no topo e
       cobriria a tabela durante a rolagem. */
    .ph-ia-grid > .ph-resumo-pedido {
        order: -1;
        position: static;
    }
}

.ph-resumo-pedido {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    position: sticky;
    /* 7.5rem, não os 1.5rem de outros cards sticky da tela: precisa ficar
       abaixo do cabeçalho .ph-ia-cabecalho (também sticky, ver acima) pra
       não sobrepor quando os dois estão grudados ao mesmo tempo — folga
       generosa pro caso do cabeçalho quebrar em 2 linhas (título + selo)
       em larguras mais estreitas dentro do breakpoint lg. */
    top: 7.5rem;
    background: linear-gradient(180deg, rgba(212, 145, 47, 0.12), rgba(212, 145, 47, 0.03)), var(--proinsight-white);
    border-color: rgba(212, 145, 47, 0.35);
    box-shadow: 0 4px 14px rgba(212, 145, 47, 0.14);
}

.ph-resumo-pedido-total {
    font-size: 1.875rem;
    font-weight: 800;
    line-height: 1.15;
    /* --ph-brand-text, não --proinsight-orange puro: mesmo problema de AA já
       corrigido em .btn-primary (issue de tokens) — 2.66:1 falha mesmo em
       texto grande (precisa 3:1). */
    color: var(--ph-brand-text);
}

/* Botão "Copiar pedido pro Mercanet" — CTA primário desta seção. A
   referência aprovada mostra laranja sólido com texto branco, mas isso
   reproduz a mesma falha de contraste (~2.66:1) já corrigida em
   .btn-primary/.ph-login-submit: aqui segue o mesmo padrão (fundo escuro,
   laranja só como glow) em vez do laranja sólido do mockup — AA é
   requisito P0 do checklist de QA do próprio pacote, prevalece sobre a cor
   exata do mockup. */
.ph-btn-mercanet {
    display: flex;
    width: 100%;
    min-height: 3rem;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    border: none;
    border-radius: 0.625rem;
    background: var(--proinsight-ink);
    /* #fff literal, não var(--proinsight-white) — mesmo bug de tema escuro
       corrigido em .btn-primary nesta mesma issue (#157): essa variável
       vira escura nos 3 temas não-claro, e o texto ficava invisível sobre
       este fundo também escuro. */
    color: #fff;
    font-family: "Montserrat App", system-ui, sans-serif;
    font-size: 0.875rem;
    font-weight: 800;
    cursor: pointer;
    transition: background-color var(--proinsight-transition-normal),
                box-shadow var(--proinsight-transition-normal);
    /* Pedido do usuário em 2026-09-20: "precisa ser bem visível... faça com
       que ele fique animado" — pulso contínuo (`infinite`), não só na
       entrada como o resto dos glows da tela (`.ph-hero-section-ia`/
       `.kpi-pulse-*`, que só pulsam 3 ciclos por causa da auditoria
       02-auditoria-ux-ui-a11y.md contra pulsação eterna): pedido explícito
       do usuário no mesmo dia ("deixar o botão pulsando") pra este botão
       específico, o CTA principal da seção — `prefers-reduced-motion`
       abaixo ainda desliga a animação, mantendo só o glow estático. */
    box-shadow: 0 0 14px rgba(212, 145, 47, 0.4);
    animation: ph-btn-mercanet-pulse 2.2s ease-in-out infinite;
}

@keyframes ph-btn-mercanet-pulse {
    0%, 100% { box-shadow: 0 0 14px rgba(212, 145, 47, 0.4), 0 0 0 0 rgba(212, 145, 47, 0.5); }
    50% { box-shadow: 0 0 14px rgba(212, 145, 47, 0.4), 0 0 0 12px rgba(212, 145, 47, 0); }
}

.ph-btn-mercanet:hover {
    background: #222222;
    box-shadow: 0 0 0 4px rgba(212, 145, 47, 0.12);
}

.ph-btn-mercanet:focus-visible {
    outline: 2px solid var(--proinsight-orange);
    outline-offset: 2px;
}

/* Toggle que revela a faixa Motivo/Evidência/Recência (oculta por padrão,
   pedido do usuário em 2026-09-19) — largura cheia, mesmo espírito visual
   da faixa que ele controla (fundo neutro sutil), pra já sinalizar "isso é
   uma barra clicável" antes mesmo do texto. O ícone-lâmpada reaproveita o
   mesmo usado no botão-lâmpada antigo (removido no redesign anterior),
   fechando a referência visual de "isso tem mais informação". */
.ph-sugestao-motivo-toggle {
    display: flex;
    width: 100%;
    align-items: center;
    gap: 0.5rem;
    border: none;
    border-top: 1px solid var(--proinsight-neutral-200);
    background: var(--proinsight-neutral-50);
    padding: 0.5rem 1.25rem;
    font-family: inherit;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--ph-text-secondary);
    cursor: pointer;
    transition: background var(--proinsight-transition-fast);
}

.ph-sugestao-motivo-toggle:hover {
    background: var(--proinsight-neutral-200);
}

.ph-sugestao-motivo-toggle:focus-visible {
    outline: 2px solid var(--ph-focus);
    outline-offset: -2px;
}

/* Chevron é sempre o último ícone renderizado (ver detalhe.php) — gruda à
   direita via margin-left:auto e gira 90° quando expandido, mesma técnica
   de affordance de outros disclosure triggers do app. */
.ph-sugestao-motivo-toggle svg:last-child {
    margin-left: auto;
    flex-shrink: 0;
    transition: transform var(--proinsight-transition-fast);
}

.ph-sugestao-motivo-toggle[aria-expanded="true"] svg:last-child {
    transform: rotate(90deg);
}

.ph-sugestao-motivo-strip {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.75rem 1.25rem;
    border-top: 1px solid var(--proinsight-neutral-200);
    background: var(--proinsight-neutral-50);
    padding: 0.75rem 1.25rem;
    font-size: 0.75rem;
}

.ph-sugestao-motivo-item {
    display: flex;
    min-width: 0;
    align-items: flex-start;
    gap: 0.5rem;
}

.ph-sugestao-motivo-icone {
    display: flex;
    height: 1.5rem;
    width: 1.5rem;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    border-radius: 9999px;
    border: 1px solid var(--proinsight-neutral-200);
    background: var(--proinsight-white);
    color: var(--ph-text-secondary);
}

.ph-sugestao-motivo-label {
    display: block;
    font-size: 0.625rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--ph-text-secondary);
}

.ph-sugestao-motivo-texto {
    color: var(--proinsight-neutral-700);
}

@media (max-width: 639px) {
    .ph-sugestao-motivo-strip {
        grid-template-columns: 1fr;
    }
}

/* Brilho pulsante nas caixas de Meta/Supermeta (pedido do usuário em
   2026-09-17: "destacar mais... deixar em uma cor que fique pulsando") —
   anel de sombra que respira pra fora, na mesma cor do ícone de cada caixa
   (azul pra Meta, violeta pra Supermeta — não uma cor nova, só reforça a já
   escolhida). Desligado com `prefers-reduced-motion` (mesmo cuidado já
   tomado no spinner de loading e no gradiente de IA do login). */
@keyframes kpi-pulse-azul {
    0%, 100% { box-shadow: 0 0 0 0 rgba(37, 99, 235, 0.55); }
    50% { box-shadow: 0 0 0 10px rgba(37, 99, 235, 0); }
}

@keyframes kpi-pulse-violeta {
    0%, 100% { box-shadow: 0 0 0 0 rgba(139, 92, 246, 0.55); }
    50% { box-shadow: 0 0 0 10px rgba(139, 92, 246, 0); }
}

/* Mesmo ajuste do glow de IA acima: pulsa só na entrada (3 ciclos), não pra
   sempre (auditoria 02-auditoria-ux-ui-a11y.md). */
.kpi-pulse-blue {
    animation: kpi-pulse-azul 2.4s ease-in-out 3;
}

.kpi-pulse-violet {
    animation: kpi-pulse-violeta 2.4s ease-in-out 3;
}

@media (prefers-reduced-motion: reduce) {
    .kpi-pulse-blue,
    .kpi-pulse-violet,
    .ph-hero-section-ia,
    .ph-btn-mercanet {
        animation: none;
    }
}

/*
 * Scrollbars finas em toda a aplicação, que "abrem" (ficam mais largas) ao
 * passar o mouse — pedido do usuário em 2026-09-10. Firefox não suporta
 * largura dinâmica no hover, então fica só fina lá (`scrollbar-width: thin`);
 * no WebKit/Blink (Chrome/Edge/Safari) a barra cresce de fato no hover.
 */
* {
    scrollbar-width: thin;
    scrollbar-color: #d4d4d4 transparent;
}

*::-webkit-scrollbar {
    width: 6px;
    height: 6px;
}

*::-webkit-scrollbar-track {
    background: transparent;
}

*::-webkit-scrollbar-thumb {
    background-color: #d4d4d4;
    border-radius: 9999px;
}

*:hover::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

*::-webkit-scrollbar-thumb:hover {
    background-color: #a3a3a3;
}

/*
 * Áreas com rolagem sem barra visível (sidebar em lib/layout.php, tabela de
 * representantes no admin) — pedido do usuário em 2026-09-10. Repete o
 * :hover com a própria classe pra sempre vencer a regra genérica acima, não
 * importa a ordem no arquivo (mesma especificidade CSS).
 */
.scroll-sem-barra {
    scrollbar-width: none;
}

.scroll-sem-barra::-webkit-scrollbar,
.scroll-sem-barra:hover::-webkit-scrollbar {
    display: none;
    width: 0;
    height: 0;
}

/* ============================================================================
   PAGE: Login (redesign 2026-09-16 — AI Sales Intelligence, ver public_html/login.php)
   ============================================================================ */

.ph-login-hero {
    background-size: cover;
    background-position: center;
}

.ph-login-hero-overlay {
    background:
        linear-gradient(180deg, rgba(11, 13, 15, 0.55) 0%, rgba(11, 13, 15, 0.72) 45%, rgba(11, 13, 15, 0.9) 100%),
        radial-gradient(ellipse at 25% 15%, rgba(212, 145, 47, 0.16), transparent 55%);
}

.ph-login-eyebrow {
    font-size: 0.6875rem;
    font-weight: 800;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.45);
}

.ph-ia-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.4rem 0.85rem;
    border-radius: 9999px;
    background: rgba(212, 145, 47, 0.08);
    border: 1px solid rgba(212, 145, 47, 0.25);
    color: #E5A94D;
    font-size: 0.6875rem;
    font-weight: 800;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.ph-ia-badge svg {
    width: 0.8125rem;
    height: 0.8125rem;
}

/* Versão clara de `.ph-ia-badge` pra usar sobre fundo branco/card (não mais
   o hero escuro do login) — pedido do usuário em 2026-09-17: um selo de IA
   único e limpo pra tela de detalhe do cliente, no lugar de um ícone +
   badge redundantes por seção ("ridículo", palavra do usuário). Mesmo
   espírito visual do badge do login (pílula, borda e fundo em tom de
   laranja translúcido, texto maiúsculo com letter-spacing), só que com
   `color: var(--proinsight-orange)` em vez do dourado claro `#E5A94D`
   (ilegível em fundo claro). */
.ph-ia-badge-light {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.3rem 0.75rem;
    border-radius: 9999px;
    background: rgba(212, 145, 47, 0.1);
    border: 1px solid rgba(212, 145, 47, 0.3);
    color: var(--ph-brand-text);
    font-size: 0.6875rem;
    font-weight: 800;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.ph-ia-badge-light svg {
    width: 0.75rem;
    height: 0.75rem;
}

.ph-login-headline {
    font-size: clamp(2.2rem, 3vw, 4rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    line-height: 1.08;
    color: #fff;
}

.ph-ia-gradient-text {
    background-image: linear-gradient(90deg, #D4912F, #F6C76C, #D4912F);
    background-size: 200% auto;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    animation: ph-ia-shimmer 6s ease-in-out infinite, ph-ia-neon-pulse 1.8s ease-in-out infinite;
}

@keyframes ph-ia-shimmer {
    0%, 100% { background-position: 0% center; }
    50% { background-position: 100% center; }
}

/* Glow neon pulsante (pedido do usuário em 2026-09-16) — soma ao shimmer
   acima, não substitui. text-shadow funciona normalmente mesmo com o texto
   preenchido por gradiente (background-clip: text; color: transparent),
   já que é uma propriedade independente do fill. Tons de laranja/dourado da
   marca (não um neon genérico ciano/magenta) pra não destoar da paleta
   reservada à identidade (Principle VII permite laranja só no login). */
@keyframes ph-ia-neon-pulse {
    0%, 100% {
        text-shadow: 0 0 8px rgba(212, 145, 47, 0.55), 0 0 18px rgba(246, 199, 108, 0.35);
    }
    50% {
        text-shadow: 0 0 16px rgba(212, 145, 47, 0.9), 0 0 34px rgba(246, 199, 108, 0.6), 0 0 50px rgba(212, 145, 47, 0.3);
    }
}

.ph-login-description {
    max-width: 520px;
    font-size: 0.9375rem;
    line-height: 1.6;
    color: rgba(255, 255, 255, 0.7);
}

.ph-flow {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

.ph-flow-pill {
    display: inline-flex;
    align-items: center;
    padding: 0.375rem 0.75rem;
    border-radius: 9999px;
    border: 1px solid rgba(255, 255, 255, 0.16);
    background: rgba(255, 255, 255, 0.04);
    color: rgba(255, 255, 255, 0.75);
    font-size: 0.75rem;
    font-weight: 600;
}

.ph-flow-pill-ia {
    border-color: rgba(212, 145, 47, 0.4);
    background: rgba(212, 145, 47, 0.12);
    color: #F6C76C;
    font-weight: 800;
}

.ph-flow-arrow {
    color: rgba(255, 255, 255, 0.28);
}

.ph-micro-benefits {
    display: flex;
    flex-wrap: wrap;
    gap: 1.25rem;
}

.ph-micro-benefit {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.75rem;
    color: rgba(255, 255, 255, 0.55);
}

.ph-micro-benefit svg {
    width: 1rem;
    height: 1rem;
    color: rgba(212, 145, 47, 0.75);
}

.ph-login-footnote {
    font-size: 0.6875rem;
    color: rgba(255, 255, 255, 0.35);
}

.ph-login-card {
    width: 100%;
    max-width: 420px;
    animation: ph-login-fade-in 500ms var(--proinsight-ease-out) both;
}

@keyframes ph-login-fade-in {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}

.ph-login-eyebrow-dark {
    font-size: 0.6875rem;
    font-weight: 800;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--proinsight-orange);
}

.ph-login-input-group {
    position: relative;
}

.ph-login-input-icon {
    position: absolute;
    left: 0.875rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--proinsight-neutral-400);
    pointer-events: none;
}

.ph-login-input-icon svg {
    width: 1.05rem;
    height: 1.05rem;
}

.ph-login-input-icon-right {
    left: auto;
    right: 0.875rem;
}

.ph-login-input-icon-com-toggle {
    left: auto;
    right: 2.75rem;
}

.ph-login-input {
    width: 100%;
    height: 3rem;
    padding-left: 0.875rem;
    padding-right: 2.75rem;
    border-radius: 0.625rem;
    border: 1px solid var(--proinsight-neutral-200);
    background: #fff;
    font-size: 0.875rem;
    color: var(--proinsight-neutral-900);
    transition: border-color 200ms var(--proinsight-ease-out), box-shadow 200ms var(--proinsight-ease-out);
}

.ph-login-input-com-toggle {
    padding-right: 4.5rem;
}

.ph-login-input::placeholder {
    color: var(--proinsight-neutral-400);
}

.ph-login-input:hover {
    border-color: var(--proinsight-neutral-400);
}

.ph-login-input:focus {
    outline: none;
    border-color: var(--proinsight-orange);
    box-shadow: 0 0 0 3px rgba(212, 145, 47, 0.1);
}

.ph-login-input-toggle {
    position: absolute;
    right: 0.625rem;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 1.75rem;
    width: 1.75rem;
    border-radius: 0.375rem;
    border: none;
    background: transparent;
    color: var(--proinsight-neutral-400);
    cursor: pointer;
    transition: color 140ms var(--proinsight-ease-out), background-color 140ms var(--proinsight-ease-out);
}

.ph-login-input-toggle svg {
    width: 1.05rem;
    height: 1.05rem;
}

/* Mostrar/ocultar senha fora do login (trocar-senha.php) — mesmo padrão do
   `.ph-login-input-toggle` acima, mas pro fundo claro/campo padrão do resto
   do app (que usa classes Tailwind soltas, não `.ph-login-input`). */
.ph-senha-toggle {
    position: absolute;
    right: 0.5rem;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 1.75rem;
    width: 1.75rem;
    border-radius: 0.375rem;
    border: none;
    background: transparent;
    color: var(--ph-text-secondary);
    cursor: pointer;
    transition: color 140ms var(--proinsight-ease-out), background-color 140ms var(--proinsight-ease-out);
}

.ph-senha-toggle:hover {
    color: var(--proinsight-neutral-700);
    background: var(--proinsight-neutral-50);
}

.ph-senha-toggle:focus-visible {
    outline: 2px solid var(--ph-focus);
    outline-offset: 2px;
}

.ph-login-input-toggle:hover {
    color: var(--proinsight-neutral-700);
    background: var(--proinsight-neutral-50);
}

.ph-login-input-toggle:focus-visible {
    outline: 2px solid var(--proinsight-orange);
    outline-offset: 2px;
}

.ph-login-submit {
    width: 100%;
    height: 3rem;
    border-radius: 0.625rem;
    border: none;
    background: #171717;
    color: #fff;
    font-family: "Montserrat App", system-ui, sans-serif;
    font-size: 0.875rem;
    font-weight: 800;
    cursor: pointer;
    transition: background-color 200ms var(--proinsight-ease-out), box-shadow 200ms var(--proinsight-ease-out);
}

.ph-login-submit:hover:not(:disabled) {
    background: #222222;
    box-shadow: 0 0 0 4px rgba(212, 145, 47, 0.12);
}

.ph-login-submit:focus-visible {
    outline: 2px solid var(--proinsight-orange);
    outline-offset: 2px;
}

.ph-login-submit:disabled {
    background: var(--proinsight-neutral-200);
    color: var(--proinsight-neutral-400);
    cursor: not-allowed;
    box-shadow: none;
}

.ph-login-security {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.375rem;
    font-size: 0.75rem;
    color: var(--proinsight-neutral-400);
}

.ph-login-security svg {
    width: 0.875rem;
    height: 0.875rem;
}

.ph-login-powered {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.6875rem;
    font-weight: 800;
    letter-spacing: 0.03em;
    color: var(--proinsight-orange);
}

.ph-login-powered svg {
    width: 0.75rem;
    height: 0.75rem;
}

@media (prefers-reduced-motion: reduce) {
    .ph-ia-gradient-text,
    .ph-login-card {
        animation: none;
    }
}

/* ============================================================================
   PAGE: Login — experiência mobile (< 768px, pedido do usuário em 2026-09-20)
   Hero em tela cheia com CTA "Entrar no ProInsight" que abre um bottom sheet
   com o MESMO formulário do desktop (phLoginFormulario(), ver
   public_html/login.php), só que com ids "-mobile" pra não colidir no DOM.
   Tudo aqui só existe dentro do wrapper `.md:hidden` (`.ph-login-mobile`) —
   nunca aparece em tablet/desktop, que continuam usando exatamente o grid de
   sempre (`.hidden.md:grid`, HTML logo acima do bloco mobile).
   ============================================================================ */

.ph-login-hero-mobile {
    min-height: 100vh; /* fallback pra navegador/WebView sem suporte a dvh */
    min-height: 100dvh;
}

/* Reportado em dispositivo real (Xiaomi Redmi Note 13, Chrome for Android,
   2026-09-20): mesmo com `100dvh`, sobrava scroll com uma área BRANCA
   embaixo do hero — o `<body>` da página de login é `bg-[#FAFAFA]`
   (claro), então qualquer folga entre o fim do hero (escuro) e o fim real
   da página (troca de estado da barra de endereço do Chrome mobile, que
   redimensiona a viewport dinamicamente e nem sempre recalcula `dvh` a
   tempo; possível também um pouco de zoom de fonte do sistema Android
   aumentando o texto) aparecia como uma faixa clara chocante. Corrigido não
   tentando perseguir um encaixe "zero pixel" impossível de garantir em
   todo aparelho/config. de fonte, e sim trocando o fundo do body por essa
   mesma cor escura do hero só no mobile — qualquer folga que sobrar mostra
   mais do próprio fundo escuro, não uma tarja branca. Só no mobile: o
   desktop/tablet (>= 768px, formulário sobre fundo claro) não é afetado. */
/* `body.ph-login-body` (não só `.ph-login-body`) de propósito — testado ao
   vivo (2026-09-20) que o <style> que o Tailwind Play CDN injeta em
   runtime acaba entrando DEPOIS de app.css no cascade (o comentário mais
   antigo sobre `.alert-compact` acima, que presumia o contrário, não se
   confirmou nesse teste) — então uma classe isolada empata em
   especificidade com `.bg-[#FAFAFA]` do Tailwind e PERDE por ordem de
   inserção. `body.ph-login-body` (elemento + classe) tem especificidade
   maior que qualquer utility de uma classe só, então ganha
   independentemente dessa ordem. */
@media (max-width: 767px) {
    body.ph-login-body {
        background: #0a0a0a;
    }
}

.ph-login-cta-mobile {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    width: 100%;
    height: 56px;
    border-radius: 16px;
    border: none;
    background: linear-gradient(135deg, #E9B368, #D4912F);
    color: #171717;
    font-family: "Montserrat App", system-ui, sans-serif;
    font-size: 1rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    cursor: pointer;
    box-shadow: 0 10px 28px rgba(212, 145, 47, 0.35);
    transition: transform 150ms var(--proinsight-ease-out), box-shadow 150ms var(--proinsight-ease-out);
}

.ph-login-cta-mobile svg {
    width: 1.1rem;
    height: 1.1rem;
}

.ph-login-cta-mobile:active {
    transform: scale(0.97);
    box-shadow: 0 4px 14px rgba(212, 145, 47, 0.3);
}

.ph-login-cta-mobile:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 3px;
}

.ph-login-sheet-backdrop {
    position: fixed;
    inset: 0;
    z-index: var(--z-modal);
    background: rgba(0, 0, 0, 0.55);
    opacity: 0;
    transition: opacity 400ms var(--proinsight-ease-out);
}

.ph-login-sheet-backdrop.is-visible {
    opacity: 1;
}

@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .ph-login-sheet-backdrop {
        backdrop-filter: blur(4px);
        -webkit-backdrop-filter: blur(4px);
    }
}

.ph-login-sheet {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: var(--z-modal-top);
    max-height: 92vh; /* fallback pra navegador/WebView sem suporte a dvh */
    max-height: 92dvh;
    overflow-y: auto;
    background: #fff;
    border-radius: 28px 28px 0 0;
    padding: 14px 24px calc(24px + env(safe-area-inset-bottom));
    transform: translateY(100%);
    transition: transform 400ms cubic-bezier(0.22, 1, 0.36, 1);
    box-shadow: 0 -16px 44px rgba(0, 0, 0, 0.28);
}

.ph-login-sheet:focus {
    outline: none;
}

.ph-login-sheet.is-visible {
    transform: translateY(0);
}

.ph-login-sheet-arraste {
    touch-action: none;
    cursor: grab;
}

.ph-login-sheet-handle {
    width: 40px;
    height: 4px;
    border-radius: 999px;
    background: var(--proinsight-neutral-200);
    margin: 0 auto 16px;
}

.ph-login-sheet-fechar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 2.25rem;
    width: 2.25rem;
    flex: none;
    border-radius: 9999px;
    border: none;
    background: var(--proinsight-neutral-50);
    color: var(--proinsight-neutral-400);
    font-size: 1.125rem;
    line-height: 1;
    cursor: pointer;
    transition: color 140ms var(--proinsight-ease-out), background-color 140ms var(--proinsight-ease-out);
}

.ph-login-sheet-fechar:hover {
    background: var(--proinsight-neutral-200);
    color: var(--proinsight-neutral-700);
}

.ph-login-sheet-fechar:focus-visible {
    outline: 2px solid var(--proinsight-orange);
    outline-offset: 2px;
}

/* font-size 16px (não os 14px padrão de .ph-login-input) só dentro do sheet
   — evita o zoom automático do Safari/iOS ao focar um campo. O formulário
   desktop (mesma classe .ph-login-input, fora do sheet) não é afetado. */
.ph-login-sheet .ph-login-input {
    font-size: 1rem;
}

body.ph-login-sheet-aberto {
    overflow: hidden;
}

/* Ajustes só de tamanho/espaçamento do conteúdo do hero (compartilhado com
   o desktop via phLoginHeroConteudo()) quando ele aparece na versão mobile —
   nunca dispara em >= 768px, onde o hero desktop/tablet já está com
   `display:none` (`.hidden` do wrapper `.md:grid`). */
@media (max-width: 767px) {
    /* Pedido do usuário em 2026-09-20 (follow-up): a 1ª versão já cabia em
       telas "normais" (iPhone 12/13, Pixel 5 etc.) só que sem folga nenhuma
       — qualquer diferença de fonte/render real (troca da fonte de fallback
       pra Montserrat, font-display:swap acima, aparelho um pouco mais baixo)
       empurrava o hero pra fora de 100dvh e a PÁGINA (não só o hero) virava
       scrollável antes mesmo de abrir o sheet. Emagrecido de novo, com uma
       folga real, não só cabendo raspando. */
    .ph-login-headline {
        font-size: clamp(1.4rem, 6vw, 1.85rem);
        line-height: 1.15;
    }

    .ph-login-description {
        font-size: 0.8125rem;
        line-height: 1.45;
    }

    .ph-flow {
        gap: 0.35rem;
    }

    .ph-flow-pill {
        padding: 0.25rem 0.6rem;
        font-size: 0.6875rem;
    }

    .ph-micro-benefits {
        gap: 0.75rem;
    }

    .ph-ia-badge {
        padding: 0.3rem 0.7rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    .ph-login-sheet,
    .ph-login-sheet-backdrop,
    .ph-login-cta-mobile {
        transition: none;
    }
}

/* ============================================================================
   Estoque do cliente, PDF e compartilhamento (specs/009, Issue #200)
   ============================================================================ */

/* Data da posição do estoque do cliente, sob os botões da ficha. */
.ph-estoque-posicao {
    font-size: 0.75rem;
    color: var(--ph-text-secondary);
}

.ph-estoque-posicao.is-desatualizado {
    color: var(--proinsight-neutral-700);
}

.ph-estoque-posicao-aviso {
    font-weight: 700;
    color: var(--ph-status-danger);
}

/* Etapas do import (enviar → conferir → pronto). */
.ph-passos {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1.25rem;
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: 0.8125rem;
    color: var(--ph-text-secondary);
}

.ph-passo {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-weight: 600;
}

.ph-passo-numero {
    display: inline-flex;
    height: 1.5rem;
    width: 1.5rem;
    align-items: center;
    justify-content: center;
    border-radius: 9999px;
    border: 1px solid var(--proinsight-neutral-200);
    background: var(--proinsight-white);
    font-size: 0.75rem;
    font-weight: 800;
}

.ph-passo.is-atual {
    color: var(--proinsight-neutral-900);
}

.ph-passo.is-atual .ph-passo-numero {
    /* neutral-900/white invertem juntos nos 4 temas (ink fixo sumia no escuro). */
    border-color: var(--proinsight-neutral-900);
    background: var(--proinsight-neutral-900);
    color: var(--proinsight-white);
}

.ph-passo.is-feito .ph-passo-numero {
    border-color: transparent;
    background: var(--ph-status-success-surface);
    color: var(--ph-status-success);
}

/* Resumo da prévia: quatro números, cor só por significado. */
.ph-previa-resumo {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem;
}

@media (min-width: 768px) {
    .ph-previa-resumo {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

.ph-previa-numero {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    border-radius: var(--radius-xl);
    border: 1px solid var(--proinsight-neutral-200);
    background: var(--proinsight-neutral-50);
    padding: 0.875rem 1rem;
}

.ph-previa-valor {
    font-size: 1.5rem;
    font-weight: 800;
    line-height: 1.1;
    color: var(--proinsight-neutral-900);
}

.ph-previa-rotulo {
    font-size: 0.8125rem;
    font-weight: 700;
    color: var(--proinsight-neutral-700);
}

.ph-previa-detalhe {
    font-size: 0.75rem;
    color: var(--ph-text-secondary);
}

.ph-previa-numero-ok {
    border-color: transparent;
    background: var(--ph-status-success-surface);
}

.ph-previa-numero-ok .ph-previa-valor {
    color: var(--ph-status-success);
}

.ph-previa-numero-atencao {
    border-color: transparent;
    background: rgba(139, 92, 246, 0.12);
}

.ph-previa-numero-erro {
    border-color: transparent;
    background: var(--ph-status-danger-surface);
}

.ph-previa-numero-erro .ph-previa-valor {
    color: var(--ph-status-danger);
}

.ph-previa-tabela thead th,
.ph-previa-detalhes thead th {
    background: var(--proinsight-neutral-50);
}

/* Ações do cabeçalho da Sugestão de pedido: Exportar PDF / Compartilhar. */
.ph-ia-acao {
    display: inline-flex;
    min-height: 2.25rem;
    align-items: center;
    gap: 0.4rem;
    border-radius: 0.5rem;
    border: 1px solid var(--proinsight-neutral-200);
    background: var(--proinsight-white);
    padding: 0.375rem 0.75rem;
    font-size: 0.8125rem;
    font-weight: 700;
    color: var(--proinsight-neutral-700);
    cursor: pointer;
    transition: border-color var(--proinsight-transition-fast), background-color var(--proinsight-transition-fast);
}

.ph-ia-acao:hover {
    border-color: var(--proinsight-neutral-400);
    background: var(--proinsight-neutral-50);
}

.ph-ia-acao:focus-visible,
.ph-compartilhar-opcao:focus-visible,
.ph-compartilhar-revogar:focus-visible {
    outline: 2px solid var(--ph-focus);
    outline-offset: 2px;
}

.ph-ia-acao-principal {
    border-color: var(--proinsight-ink);
    background: var(--proinsight-ink);
    color: #fff;
}

.ph-ia-acao-principal:hover {
    border-color: #222222;
    background: #222222;
    box-shadow: 0 0 0 4px rgba(212, 145, 47, 0.12);
}

/* Diálogo "Compartilhar sugestão de pedido". */
.ph-compartilhar-card {
    max-width: 36rem;
}

.ph-compartilhar-opcoes {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.5rem;
}

@media (min-width: 560px) {
    .ph-compartilhar-opcoes {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

.ph-compartilhar-opcao {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    border-radius: var(--radius-xl);
    border: 1px solid var(--proinsight-neutral-200);
    background: var(--proinsight-white);
    padding: 0.625rem 0.75rem;
    font-size: 0.8125rem;
    color: var(--proinsight-neutral-900);
    text-decoration: none;
    transition: border-color var(--proinsight-transition-fast), background-color var(--proinsight-transition-fast);
}

.ph-compartilhar-opcao:hover {
    border-color: var(--proinsight-neutral-400);
    background: var(--proinsight-neutral-50);
}

.ph-compartilhar-opcao-icone {
    display: inline-flex;
    height: 2rem;
    width: 2rem;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    border-radius: 0.5rem;
    background: var(--proinsight-neutral-50);
    color: var(--proinsight-neutral-700);
}

.ph-compartilhar-opcao-whatsapp {
    background: rgba(37, 211, 102, 0.14);
    color: #128c4a;
}

.ph-compartilhar-revogar {
    border-radius: 0.5rem;
    border: 1px solid var(--proinsight-neutral-200);
    background: transparent;
    padding: 0.25rem 0.625rem;
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--proinsight-neutral-700);
    cursor: pointer;
}

.ph-compartilhar-revogar:hover,
.ph-compartilhar-revogar.is-confirmando {
    border-color: var(--ph-status-danger);
    color: var(--ph-status-danger);
}

.ph-compartilhar-revogar.is-confirmando {
    background: var(--ph-status-danger-surface);
}

.ph-compartilhar-revogar:disabled {
    opacity: 0.6;
    cursor: progress;
}

#ph-compartilhar-pronto:not([hidden]) {
    animation: ph-compartilhar-entrar 200ms var(--proinsight-ease-out);
}

@keyframes ph-compartilhar-entrar {
    from {
        opacity: 0;
        transform: translateY(4px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    #ph-compartilhar-pronto:not([hidden]) {
        animation: none;
    }
}
