/* ult.css — o MEDIDOR da ultimate no HUD da corrida e o VÉU dos 30 s (docs/specs/ultimate.md §6.1, §6.2; ui/widgets/ultGauge.js).

   ONDE (px de arte do palco 640×360; no celular deitado 48 px CSS, ~8 mm; no PC 96):
     medidor  x 132…180 · y 308…356 com 5 slots na barra (com 3, acompanha a coluna): o pino `.hud-ult-pin` (0×0, absoluto) é filho
              de `.hud-bar-col`; sem `top`/`left` ele fica no x da coluna (a posição estática de filho absoluto de flex) e o
              `bottom: 0` o assenta no pé da `.hud-bottom` (y 356, o pé dos slots). O botão mora à ESQUERDA dele, 6 px antes da
              barra. A coluna não vira bloco de contenção (o `.ability-tip` mede `left` a partir da `.hud-bottom`) e o pino, fora do
              fluxo, não soma o vão de 2 px da coluna: a barra e as poções não se movem.
     véu      o palco inteiro, 1.º filho de `#hud` (sob os widgets), sem toque.
   A cor da classe (`--ult-rgb`) vem da classe `ult-c-<classKey>` (o medidor, o véu e a linha do quadro do Grupo) e é UMA fonte só:
   o `num` de `game/view/spiritColors.js` (a cor do número do espírito, rampa:tom no comentário) — a UI não importa `game/view`, então
   a tabela é cópia, e `ultGauge.test.js` prova que é igual. Classe ou tom novo: mude lá e copie aqui. Por ser o `num`, cada cor é um
   tom da paleta mestra, fica a ΔE00 ≥ 12 das cores do número e do ouro do "pede ação" (`--c-gold`): no Grupo nada pede ação. */

.ult-c-warrior { --ult-rgb: 245, 106, 16; }        /* fire:2 */
.ult-c-mage { --ult-rgb: 208, 112, 255; }          /* arcane:3 */
.ult-c-archer { --ult-rgb: 106, 166, 181; }        /* mithril:2 */
.ult-c-artist { --ult-rgb: 204, 144, 238; }        /* cloth_purple:4 */
.ult-c-giant { --ult-rgb: 244, 220, 170; }         /* sand:4 */
.ult-c-summoner { --ult-rgb: 192, 255, 216; }      /* gem_emerald:4 */
.ult-c-hunter { --ult-rgb: 196, 206, 180; }        /* moss:4 */
.ult-c-lancer { --ult-rgb: 247, 131, 90; }         /* cloth_red:4 */
.ult-c-justicar { --ult-rgb: 255, 248, 200; }      /* holy:3 */
.ult-c-reaper { --ult-rgb: 242, 184, 150; }        /* dusk:4 */
.ult-c-rogue { --ult-rgb: 90, 154, 24; }           /* poison:2 */
.ult-c-bard { --ult-rgb: 255, 245, 168; }          /* gold:4 */
.ult-c-chronomancer { --ult-rgb: 168, 219, 224; }  /* mithril:3 */
.ult-c-electromancer { --ult-rgb: 232, 200, 255; } /* gem_amethyst:4 */

/* ---- o medidor ------------------------------------------------------------------------------------------------------------- */
.hud-ult-pin {
  position: absolute;
  bottom: 0;
  width: 0;
  height: 0;
}
.hud-ult {
  position: absolute;
  right: calc(6 * var(--px));
  bottom: 0;
  width: calc(48 * var(--px));
  height: calc(48 * var(--px));
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--c-text);
  cursor: pointer;
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.hud-ult[aria-disabled='true'] { cursor: default; }
.hud-ult:focus-visible { outline: var(--px) solid var(--c-text); outline-offset: var(--px); }
.hud-ult-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  image-rendering: pixelated;
  pointer-events: none;
}
/* O provisório (a folha não carregou, classe sem medidor): um frasco 40×40 que enche de baixo na cor da classe. */
.hud-ult-prov {
  display: none;
  position: absolute;
  inset: calc(4 * var(--px));
  background: rgba(10, 8, 14, 0.78);
  box-shadow: inset 0 0 0 var(--px) rgba(var(--ult-rgb, 176, 168, 152), 0.9), 0 0 0 var(--px) #000;
  pointer-events: none;
}
.hud-ult-prov::after {
  content: '';
  position: absolute;
  left: calc(2 * var(--px));
  right: calc(2 * var(--px));
  bottom: calc(2 * var(--px));
  height: calc((36 * var(--px)) * var(--ult-fill, 0));
  background: rgba(var(--ult-rgb, 176, 168, 152), 0.85);
}
.hud-ult.is-prov > .hud-ult-prov { display: block; }
/* a cheia que pisca ~3 s, no provisório (com a arte, quem pisca são os quadros `rdy`) */
.hud-ult.is-ready.is-blink > .hud-ult-prov { animation: ult-prov-blink 0.5s steps(2, jump-none) infinite alternate; }
@keyframes ult-prov-blink {
  from { filter: brightness(1); }
  to   { filter: brightness(1.5); }
}
.hud-ult-sec {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: var(--text-2);
  line-height: 1;
  text-shadow: var(--px) var(--px) 0 #000;
  pointer-events: none;
}
/* O selo do automático: o `ico_auto` 8×8 no canto ↗ (x 40…47 · y 0…7), que a arte deixa vazio em todo estado. */
.hud-ult-auto {
  display: none;
  position: absolute;
  right: 0;
  top: 0;
  width: calc(8 * var(--px));
  height: calc(8 * var(--px));
  background: var(--ui-ico_auto) no-repeat center / 100% 100%;
  image-rendering: pixelated;
  pointer-events: none;
}
.hud-ult.is-auto > .hud-ult-auto { display: block; }
/* A tecla no canto ↖, DENTRO do medidor (x 133 · y 308), só na cheia (é quando ela faz algo) e só onde há teclado. Fora dele
   (x 130) ela ficava a 2 px do fim das linhas do feed (x 128) e se lia como parte da linha; dentro, o contorno de 1 px a separa
   da arte (o canto ↖ é vazio em 11 das 14 folhas; o ↗ é do selo do automático). */
.hud-ult-key {
  display: none;
  position: absolute;
  left: calc(1 * var(--px));
  top: 0;
  font-size: var(--text-1);
  line-height: 1;
  color: var(--c-text);
  text-shadow: var(--px) 0 0 #000, calc(-1 * var(--px)) 0 0 #000, 0 var(--px) 0 #000, 0 calc(-1 * var(--px)) 0 #000;
  pointer-events: none;
}
.hud-ult.is-ready > .hud-ult-key { display: block; }
@media (hover: none) and (pointer: coarse) {
  .hud-ult.is-ready > .hud-ult-key { display: none; }
}

/* Os estados (a imagem é do canvas; aqui só o que vive em volta dela). */
.hud-ult.is-dead > .hud-ult-canvas,
.hud-ult.is-dead > .hud-ult-prov { filter: grayscale(1) brightness(0.45); }
/* cheia em descanso: o `rdy1` parado com um respiro lento de 2 s (nunca pisca sem fim) */
.hud-ult.is-ready.is-rest > .hud-ult-canvas { animation: ult-rest 2s steps(4, jump-none) infinite alternate; }
@keyframes ult-rest {
  from { filter: brightness(1); }
  to   { filter: brightness(1.18); }
}
/* ativa: o objeto respira na cor da classe */
.hud-ult.is-active > .hud-ult-canvas { filter: drop-shadow(0 0 var(--px) rgba(var(--ult-rgb, 176, 168, 152), 0.9)); }
/* o pop da cheia, e o curto do abate de elite ou chefe enchendo */
.hud-ult.is-ready-pop > .hud-ult-canvas,
.hud-ult.is-ready-pop > .hud-ult-prov { animation: ult-pop 0.14s steps(2, jump-none) both; }
@keyframes ult-pop {
  from { filter: brightness(1.9); }
  to   { filter: brightness(1); }
}
/* o toque mandado, esperando o op 1 (teto 500 ms) */
.hud-ult.is-queued { outline: var(--px) solid var(--c-gold); outline-offset: calc(-1 * var(--px)); }
/* a recusa: o tremor de 2 px por 150 ms em `transform` (o `.is-deny` de hud.css anda por `left`, que aqui brigaria com o `right`) */
.hud-ult.is-deny { animation: ult-deny 0.15s steps(3, jump-none); }
@keyframes ult-deny {
  0%   { transform: translateX(calc(2 * var(--px))); }
  50%  { transform: translateX(calc(-2 * var(--px))); }
  100% { transform: none; }
}

/* ---- o véu dos 30 s (só o SEU herói; a cena nunca o toca) ------------------------------------------------------------------- */
.ult-veil {
  display: none;
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* a borda interna na cor da classe a 12 % e o escurecido radial de 8 % */
  box-shadow: inset 0 0 calc(24 * var(--px)) calc(4 * var(--px)) rgba(var(--ult-rgb, 176, 168, 152), 0.12);
  background: radial-gradient(ellipse at center, transparent 55%, rgba(0, 0, 0, 0.08) 100%);
}
.ult-veil.is-on { display: block; animation: ult-veil-breathe 1.6s steps(8, jump-none) infinite alternate; }
.ult-veil.is-on.is-final { animation-duration: 0.5s; }
@keyframes ult-veil-breathe {
  from { opacity: 1; }
  to   { opacity: 0.6; }
}
/* a piscada da ativação: a borda a 40 % que cai até a de sempre (12 %) em 400 ms */
.ult-veil.is-flash::after {
  content: '';
  position: absolute;
  inset: 0;
  box-shadow: inset 0 0 calc(24 * var(--px)) calc(8 * var(--px)) rgba(var(--ult-rgb, 176, 168, 152), 0.4);
  animation: ult-veil-flash 0.4s steps(6, jump-none) both;
}
@keyframes ult-veil-flash {
  from { opacity: 1; }
  to   { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .hud-ult.is-ready.is-rest > .hud-ult-canvas,
  .hud-ult.is-ready.is-blink > .hud-ult-prov,
  .hud-ult.is-ready-pop > .hud-ult-canvas,
  .hud-ult.is-ready-pop > .hud-ult-prov,
  .hud-ult.is-deny,
  .ult-veil.is-on { animation: none; }
  .ult-veil.is-flash::after { display: none; }
}
