/* Visuais animados de /services/infraestrutura (prefixo infra-). Markup: templates/services/_infra_visuals.html.
   Estado base = FINAL e estatico (reduced-motion e sem JS). Movimento so em @media (prefers-reduced-motion: no-preference).
   Animacoes continuas: apenas transform, opacity e stroke-dashoffset. Pausa: classe .is-paused (posta pelo JS fora da tela / aba oculta). */

.infra-fig {
  --infra-fs: 15px;           /* tamanho do texto em unidades do viewBox; subido em telas menores (escala < 1) */
  --infra-fs-lg: 17px;
  --infra-fs-num: 34px;
  padding: var(--space-3);
}
.infra-svg { display: block; width: 100%; height: auto; overflow: hidden; }
.infra-fig--net .infra-svg  { aspect-ratio: 520 / 400; }
.infra-fig--wifi .infra-svg { aspect-ratio: 520 / 400; }
.infra-fig--virt .infra-svg { aspect-ratio: 520 / 410; }

/* Tamanho do texto: efetivo >= 12px em cada largura (medido por script em 320, 390, 600, 768, 861, 1000, 1440) */
@media (max-width: 1199px) { .infra-fig { --infra-fs: 18px; --infra-fs-lg: 20px; } }
@media (max-width: 999px)  { .infra-fig { --infra-fs: 23px; --infra-fs-lg: 26px; --infra-fs-num: 40px; } }
@media (max-width: 860px)  { .infra-fig { --infra-fs: 15px; --infra-fs-lg: 17px; --infra-fs-num: 34px; } }
@media (max-width: 560px)  { .infra-fig { --infra-fs: 19px; --infra-fs-lg: 21px; --infra-fs-num: 38px; } }
@media (max-width: 400px)  { .infra-fig { --infra-fs: 24px; --infra-fs-lg: 26px; --infra-fs-num: 44px; } }

/* Hero (rede): viewBox recortado em 441 unidades de largura; texto efetivo medido >= 12px em 320, 390, 768 e 1440 */
.infra-fig--net { --infra-fs: 13.1px; }
@media (max-width: 1199px) { .infra-fig--net { --infra-fs: 16.6px; } }
@media (max-width: 999px)  { .infra-fig--net { --infra-fs: 20.6px; } }
@media (max-width: 860px)  { .infra-fig--net { --infra-fs: 11.4px; } }
@media (max-width: 560px)  { .infra-fig--net { --infra-fs: 17.2px; } }
@media (max-width: 400px)  { .infra-fig--net { --infra-fs: 23px; } }

/* Texto ------------------------------------------------------------------ */
.infra-lbl { font-family: var(--font-mono); font-size: var(--infra-fs); font-weight: 500; fill: var(--navy-900); letter-spacing: 0; }
.infra-lbl--inv { fill: #fff; }
.infra-lbl--title { font-size: var(--infra-fs-lg); font-weight: 600; }
.infra-lbl--halo { paint-order: stroke; stroke: var(--surface); stroke-width: 4px; stroke-linejoin: round; font-weight: 600; }
.infra-lbl--hot { fill: var(--orange-600); opacity: 0; transform-box: fill-box; transform-origin: center; }
.infra-num { font-family: var(--font-mono); font-size: var(--infra-fs-num); font-weight: 500; fill: var(--navy-900); letter-spacing: -0.02em; }
.infra-unit { fill: var(--ink-700); }
.infra-cpu { fill: var(--ink-700); }

/* Blocos comuns ------------------------------------------------------------ */
/* Solidos isometricos (macro prism): 3 faces derivadas de --c. topo mais claro, esquerda media, direita escura. Sem degrade. */
.infra-pr { --c: color-mix(in srgb, var(--navy-500) 26%, #fff); }
.infra-pr polygon, .infra-ap-disc ellipse, .infra-ap-disc rect { stroke: var(--navy-900); stroke-width: 1; stroke-linejoin: round; }
.infra-f-t { fill: color-mix(in srgb, var(--c), #fff 38%); }
.infra-f-l { fill: var(--c); }
.infra-f-r { fill: color-mix(in srgb, var(--c), #000 34%); }
.infra-ap-disc { --c: color-mix(in srgb, var(--navy-500) 26%, #fff); }
.infra-pr--light { --c: color-mix(in srgb, var(--navy-500) 14%, #fff); }
.infra-pr--paper { --c: #fff; }
.infra-pr--dark { --c: var(--navy-900); }
.infra-pr--hw { --c: color-mix(in srgb, var(--ink-500) 30%, #fff); }
.infra-pr--hyp { --c: var(--navy-700); }
.infra-pr--vmware { --c: var(--navy-900); }
.infra-pr--hyperv { --c: var(--navy-500); }
.infra-pr--proxmox { --c: var(--ink-500); }
.infra-pr--docker { --c: var(--orange-600); }
.infra-pr--dark polygon, .infra-pr--vmware polygon { stroke: color-mix(in srgb, var(--navy-500) 60%, #fff); stroke-width: 0.9; }
.infra-depth { --k: 0; }
.infra-depth--0 { --k: 2; } .infra-depth--1 { --k: 4; } .infra-depth--2 { --k: 6; }
.infra-ports polygon { fill: var(--navy-900); stroke: none; opacity: 0.7; }
.infra-ports .infra-led { fill: var(--orange-500); opacity: 1; }
.infra-led { fill: var(--navy-500); stroke: none; }
.infra-slot { fill: var(--navy-900); opacity: 0.6; stroke: none; }
.infra-screen { fill: color-mix(in srgb, var(--navy-500) 22%, #fff); stroke: var(--navy-900); stroke-width: 0.8; }
.infra-ap-dot { fill: var(--navy-900); stroke: none; }
.infra-wifi { stroke: var(--navy-700); stroke-width: 1.75; stroke-linecap: round; }
.infra-key { stroke: none; }
.infra-legend .infra-lbl { fill: var(--ink-700); }

/* 1) Rede (isometrica) ------------------------------------------------------ */
.infra-grid { stroke: var(--line); stroke-width: 0.9; }
.infra-track { stroke: var(--navy-500); stroke-opacity: 0.3; stroke-width: 8; stroke-linejoin: round; }
.infra-link { stroke: var(--navy-500); stroke-opacity: 0.55; stroke-width: 1.25; stroke-linejoin: round; }
.infra-pkt { stroke: var(--navy-700); stroke-width: 6; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 0.1 var(--g, 40); stroke-dashoffset: 0; }
.infra-pkt--calm { stroke: var(--navy-500); }
/* halo claro sob cada pacote (mesmo dash/animacao) */
.infra-pkt--halo { stroke: #fff; stroke-opacity: 0.95; stroke-width: 9.5; }
.infra-hot-glow, .infra-hot { stroke: var(--orange-600); stroke-linecap: round; stroke-linejoin: round; opacity: 0; }
.infra-hot-glow { stroke-width: 10; stroke-opacity: 0.35; }
.infra-hot { stroke-width: 6; stroke-dasharray: 0.1 var(--g, 40); }
.infra-hot--halo { stroke: #fff; stroke-opacity: 0.95; stroke-width: 9.5; }
.infra-pulse { fill: none; stroke: var(--navy-500); stroke-width: 1.5; opacity: 0; transform-box: fill-box; transform-origin: center; }
.infra-brick { stroke: #fff; stroke-opacity: 0.32; stroke-width: 1; }
.infra-cloud__o * { fill: var(--navy-900); stroke: var(--navy-900); stroke-width: 2.6; stroke-linejoin: round; }
.infra-cloud__f * { fill: #fff; stroke: none; }

/* 2) Site survey ------------------------------------------------------------ */
.infra-floor { fill: var(--surface); }
.infra-walls path, .infra-walls__outer { stroke: var(--ink-700); stroke-width: 2.5; stroke-linecap: round; }
.infra-walls__outer { stroke: var(--navy-900); stroke-width: 3; }
/* Mapa de calor em bandas opacas (camadas fraco > medio > forte, sem mistura entre APs) */
.infra-heat__weak circle { fill: color-mix(in srgb, var(--orange-500) 15%, #fff); }
.infra-heat__mid circle { fill: color-mix(in srgb, var(--navy-500) 17%, #fff); }
.infra-heat__strong circle { fill: color-mix(in srgb, var(--navy-700) 30%, #fff); }
.infra-heat circle { transform-box: fill-box; transform-origin: center; }
.infra-ring { stroke: var(--navy-500); stroke-width: 1.5; vector-effect: non-scaling-stroke; opacity: 0; transform-box: fill-box; transform-origin: center; }
.infra-ap { fill: var(--surface); stroke: var(--navy-900); stroke-width: 2; }
.infra-ap__core { fill: var(--navy-900); }
.infra-dot { fill: var(--navy-500); stroke: var(--surface); stroke-width: 1.5; }
.infra-dot.is-strong { fill: var(--navy-900); }
.infra-dot.is-mid { fill: var(--navy-500); }
.infra-dot.is-weak { fill: var(--orange-600); }
.infra-route { stroke: none; }
.infra-walker__halo { fill: var(--orange-600); fill-opacity: 0.2; }
.infra-walker__dot { fill: var(--orange-600); stroke: var(--surface); stroke-width: 2.5; }
.infra-bar { fill: var(--navy-900); }
.infra-bar--2 { fill: var(--navy-900); } .infra-bar--3 { fill: var(--navy-900); }
.infra-reader.is-weak .infra-num { fill: var(--orange-700); }
.infra-reader.is-weak .infra-bar--2, .infra-reader.is-weak .infra-bar--3 { fill: var(--line); }
.infra-reader.is-mid .infra-bar--3 { fill: var(--line); }
.infra-key--strong { fill: var(--navy-900); }
.infra-key--mid { fill: var(--navy-500); }
.infra-key--weak { fill: var(--orange-600); }

/* 3) Virtualizacao (isometrica) --------------------------------------------- */
.infra-fig--virt .infra-track { stroke: none; fill: var(--line); }
.infra-fill { fill: var(--navy-700); transform-box: fill-box; transform-origin: center bottom; }
.infra-fill--hot { fill: var(--orange-600); opacity: 0; }
.infra-slotd { fill: none; stroke: var(--ink-500); stroke-width: 1.4; stroke-dasharray: 4 4; stroke-linejoin: round; opacity: 0.85; }
.infra-slotd[data-role="slot-dst"] { opacity: 0; }
.infra-arc { stroke: var(--orange-600); stroke-width: 2; stroke-dasharray: 3 6; stroke-linecap: round; opacity: 0.55; }
.infra-mover polygon { stroke: var(--orange-600); stroke-width: 1.8; }
.infra-key--vmware { fill: var(--navy-900); }
.infra-key--hyperv { fill: var(--navy-500); }
.infra-key--proxmox { fill: var(--ink-500); }
.infra-key--docker { fill: var(--orange-600); }
.infra-key--hyp { fill: var(--navy-700); }
.infra-key--hw { fill: color-mix(in srgb, var(--ink-500) 30%, #fff); stroke: var(--ink-500); stroke-width: 1; }

/* Movimento ------------------------------------------------------------------ */
@media (prefers-reduced-motion: no-preference) {
  /* Rede: pacotes por stroke-dashoffset; velocidade = (gap) / duracao, diferente por link */
  .infra-pkt { animation: infra-flow var(--d, 2s) linear var(--o, 0s) infinite; }
  @keyframes infra-flow { to { stroke-dashoffset: calc(var(--dir, 1) * (var(--g, 20) + 0.1) * -1); } }

  /* Pico de trafego (ciclo de 10 s; o delay de 1.5 s e o mesmo em todas as pecas, ficam em fase):
     2,0 a 3,0 s o link Core->Acesso vira laranja; 3,0 a 3,4 s o rotulo 'pico' entra (fade + escala, 400 ms);
     fica legivel ate 6,6 s (3,6 s); 6,6 a 7,1 s o rotulo some (500 ms) junto com a volta do link ao normal. */
  .infra-hot-glow { animation: infra-hot-fade 10s ease-in-out 1.5s infinite; }
  .infra-hot { animation: infra-hot-fade 10s ease-in-out 1.5s infinite, infra-flow var(--dh, 1.2s) linear infinite; }
  .infra-lbl--hot { animation: infra-pico 10s ease-out 1.5s infinite; }
  @keyframes infra-hot-fade { 0%, 20%, 71%, 100% { opacity: 0; } 30%, 66% { opacity: 1; } }
  @keyframes infra-pico {
    0%, 30% { opacity: 0; transform: scale(0.85); }
    34%, 66% { opacity: 1; transform: scale(1); }
    71%, 100% { opacity: 0; transform: scale(1); }
  }
  /* o pacote calmo do mesmo link some durante o pico (no maximo 3 pacotes por link) */
  .infra-pkt--calm { animation: infra-flow var(--d, 2s) linear var(--o, 0s) infinite, infra-calm-fade 10s ease-in-out 1.5s infinite; }
  @keyframes infra-calm-fade { 0%, 20%, 71%, 100% { opacity: 1; } 30%, 66% { opacity: 0; } }

  /* Firewall filtrando: pulso discreto */
  .infra-pulse { animation: infra-pulse 3.4s ease-out 0.4s infinite; }
  @keyframes infra-pulse { 0% { opacity: 0.6; transform: scale(1); } 70%, 100% { opacity: 0; transform: scale(1.3); } }

  .infra-wifi--1 { animation: infra-blink 2.4s ease-in-out infinite; }
  .infra-wifi--2 { animation: infra-blink 2.4s ease-in-out 0.35s infinite; }
  @keyframes infra-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

  /* Survey: ondas dos APs (3 aneis defasados) e calor que respira */
  .infra-ring { animation: infra-ring 3.6s linear var(--o, 0s) infinite; }
  @keyframes infra-ring { 0% { opacity: 0.7; transform: scale(1); } 100% { opacity: 0; transform: scale(12); } }
  .infra-heat circle { animation: infra-breathe 6s ease-in-out infinite alternate; }
  .infra-heat circle:nth-child(2) { animation-delay: -1.5s; } .infra-heat circle:nth-child(3) { animation-delay: -3s; } .infra-heat circle:nth-child(4) { animation-delay: -4.5s; }
  @keyframes infra-breathe { from { transform: scale(0.97); } to { transform: scale(1.04); } }

  /* Dots de medicao e containers: transicoes de entrada (classes postas pelo JS) */
  .infra-dot { transition: opacity 0.3s ease-out, transform 0.3s ease-out; transform-box: fill-box; transform-origin: center; }
  .infra-fig.is-live .infra-dot.is-hidden { opacity: 0; transform: scale(0.3); }

  /* Profundidade leve (so mouse): 3 camadas deslocam ate 6px; --px/--py (-1..1) vem do JS; so transform */
  @media (hover: hover) and (pointer: fine) {
    .infra-fig--net .infra-depth, .infra-fig--virt .infra-depth {
      transform: translate(calc(var(--px, 0) * var(--k) * -1px), calc(var(--py, 0) * var(--k) * -1px));
      transition: transform 0.4s ease-out;
    }
  }

  .infra-fig.is-paused *, .infra-fig.is-paused *::before { animation-play-state: paused !important; }
}

@media (prefers-reduced-motion: reduce) {
  .infra-fig *, .infra-fig *::before { animation: none !important; transition: none !important; }
}
