# Alocação WMS — Fluxo Simplificado — Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Tornar a bipagem da Alocação WMS 100% manual — o modo escolhido vira o campo-alvo fixo de todo bipe (sem inferência nem auto-avanço), e bipes repetidos do mesmo produto somam a quantidade.

**Architecture:** Refatoração **somente frontend** do IIFE em `item.js` e da view `item.php`. O modelo de dados e o backend (`MissoesBipagem::alocarLocalizacao`, `ConfirmarAlocacaoLaboratorio`, Sonda, validator) ficam **intactos** — 1 Confirmar continua gravando 1 linha em `wms_alocacoes` e marcando o item `concluído`, recebendo a `quantidade` final acumulada pelo front.

**Tech Stack:** PHP 8 (views Galaxia), JavaScript (jQuery 3.7.1, IIFE inline via `<?php include ?>`), CSS inline.

## Global Constraints

- **Backend imutável:** nenhuma alteração em PHP de domínio (Sondas, Laboratórios, Validators, Satélites, Migrations). Só `item.js` e `item.php`.
- **Spec de referência:** `docs/superpowers/specs/2026-06-22-alocacaowms-fluxo-simplificado-design.md`.
- **Sem testes automatizados de JS** neste repo → verificação é **manual no navegador** (mobile/scanner). Cada task termina com checklist de verificação manual.
- **i18n:** textos de view via `show('texto em PT literal')` (chave = md5 do texto; auto-harvest); validar no navegador. Toasts no JS seguem o padrão existente (string PT hardcoded no `item.js`).
- **`item.js` é inline** (`<script><?php include __DIR__ . '/item.js'; ?></script>`) → **não precisa** de cache-bust `?v=N`.
- **Commits:** o projeto **não** commita sem pedido explícito do usuário. Os passos de commit abaixo só executam quando o usuário autorizar.
- **Padrão de código:** manter o estilo do arquivo (IIFE, funções `_privadas`, jQuery, comentários em PT).

---

### Task 1: Modo = campo-alvo fixo (remove inferência e auto-avanço) + indicador de modo

Remove a heurística de campo (`_decidirAlvo`/`_campoDoPasso`) e o avanço automático (`_avancarPasso`, `estado.passo`). O modo selecionado passa a definir o campo-alvo de **todo** bipe; o toque no campo oposto redireciona **1 bipe e volta** (já que os setters limpam `campoAtivo`). Troca o indicador de passos por um indicador de modo na view.

**Files:**
- Modify: `componentes/Missoes/Logistica/sinais/App/html/alocacaowms/item.js`
- Modify: `componentes/Missoes/Logistica/sinais/App/html/alocacaowms/item.php`

**Interfaces:**
- Produces: `_alvoAtual(): 'produto'|'localizacao'` (substitui `_decidirAlvo`); `_renderEstado()` agora rende o indicador de modo (`#wms-modo-atual-label`) e o destaque do campo-alvo. `estado.passo` deixa de existir.
- Consumes: `estado.modo` (`'produto'|'endereco'`), `estado.campoAtivo` (override por toque), `codigosBarrasMap`.

- [ ] **Step 1: `item.js` — remover `estado.passo`**

Em `var estado = { ... }`, apagar a linha:

```js
        passo:         0,     // 0=aguardando modo, 1=passo1, 2=passo2
```

- [ ] **Step 2: `item.js` — substituir `_decidirAlvo` + `_campoDoPasso` por `_alvoAtual`**

Substituir o bloco das duas funções (`function _decidirAlvo() { ... }` e `function _campoDoPasso() { ... }`) por:

```js
    // Campo-alvo de todo bipe: override por toque (1 bipe) vence; senão o campo do modo.
    // Modo 'produto' → campo Produto; modo 'endereco' → campo Localização. Nunca infere por conteúdo.
    function _alvoAtual() {
        if (estado.campoAtivo === 'produto' || estado.campoAtivo === 'localizacao') {
            return estado.campoAtivo;
        }
        return estado.modo === 'produto' ? 'produto' : 'localizacao';
    }
```

- [ ] **Step 3: `item.js` — `_processarCodigo` roteia por `_alvoAtual` (sem avançar passo)**

Substituir a função `_processarCodigo` por:

```js
    function _processarCodigo(codigo, origem) {
        if (!codigo) return;
        if (!estado.modo) {
            _mostrarToast('info', 'Selecione como deseja bipar primeiro.');
            return;
        }

        var alvo = _alvoAtual();

        if (alvo === 'produto') {
            _resolverESetarProduto(codigo, origem);
        } else if (alvo === 'localizacao') {
            if (estado.localizacaoCodigo) _limparLocalizacao();
            _setLocalizacao(codigo, origem);
        }
    }
```

- [ ] **Step 4: `item.js` — `_setProdutoCodigo` sem auto-avanço**

Substituir a função `_setProdutoCodigo` por:

```js
    function _setProdutoCodigo(codigo, origem) {
        estado.produtoCodigo  = codigo;
        estado.produtoOrigem  = origem;
        estado.campoAtivo = null;
        _setExibicaoProduto(codigo, '');
        $('#campo-produto').addClass('preenchido').removeClass('ativo');
        _atualizarBotaoConfirmar();
        _renderEstado();
    }
```

- [ ] **Step 5: `item.js` — `_setLocalizacao` sem auto-avanço**

Substituir a função `_setLocalizacao` por:

```js
    function _setLocalizacao(codigo, origem) {
        estado.localizacaoCodigo = codigo;
        estado.localizacaoOrigem = origem;
        estado.campoAtivo = null;
        $('#localizacao-valor').text(codigo).removeClass('vazio');
        $('#campo-localizacao').addClass('preenchido').removeClass('ativo');
        _atualizarBotaoConfirmar();
        _renderEstado();
    }
```

- [ ] **Step 6: `item.js` — `_selecionarItemPorElemento` sem auto-avanço**

No final da função `_selecionarItemPorElemento`, substituir o bloco:

```js
        // Avança passo se estamos em passo 1 (produto como alvo)
        if (_campoDoPasso() === 'produto' && estado.passo === 1) {
            _avancarPasso();
        }

        _atualizarBotaoConfirmar();
    }
```

por:

```js
        _renderEstado();
        _atualizarBotaoConfirmar();
    }
```

- [ ] **Step 7: `item.js` — `_resolverESetarProduto` sem o parâmetro/efeito de avanço**

Trocar a assinatura `function _resolverESetarProduto(codigo, origem, avancarAposResolucao) {` por `function _resolverESetarProduto(codigo, origem) {` e, no final da função, substituir:

```js
        if (avancarAposResolucao) {
            _avancarPasso();
        }
        _atualizarBotaoConfirmar();
    }
```

por:

```js
        _renderEstado();
        _atualizarBotaoConfirmar();
    }
```

- [ ] **Step 8: `item.js` — remover `_avancarPasso`**

Apagar a função inteira:

```js
    function _avancarPasso() {
        if (estado.passo === 1) {
            estado.passo = 2;
            estado.campoAtivo = null;
            _renderEstado();
            var campo2 = _campoDoPasso();
            if (campo2) {
                setTimeout(function () {
                    var $el = $('#campo-' + campo2);
                    if ($el.length) {
                        $el[0].scrollIntoView({ behavior: 'smooth', block: 'center' });
                    }
                }, 150);
            }
        }
    }
```

- [ ] **Step 9: `item.js` — `_renderEstado` rende indicador de modo**

Substituir a função `_renderEstado` por:

```js
    function _renderEstado() {
        if (!estado.modo) {
            $('#wms-modo-selector').show();
            $('#wms-bipagem-container').hide();
            return;
        }

        $('#wms-modo-selector').hide();
        $('#wms-bipagem-container').show();

        // Rótulo do modo atual
        var ehProduto = estado.modo === 'produto';
        $('#wms-modo-atual-label').text(ehProduto ? 'PRODUTO' : 'ENDEREÇO');

        // Destaque do campo-alvo atual (modo + override por toque)
        $('#campo-produto, #campo-localizacao').removeClass('ativo');
        var alvo = _alvoAtual();
        $('#campo-' + (alvo === 'localizacao' ? 'localizacao' : 'produto')).addClass('ativo');
    }
```

- [ ] **Step 10: `item.js` — `_carregarModoSalvo` sem passo**

Substituir o bloco dentro de `_carregarModoSalvo`:

```js
            if (salvo === 'produto' || salvo === 'endereco') {
                estado.modo  = salvo;
                estado.passo = 1;
            }
```

por:

```js
            if (salvo === 'produto' || salvo === 'endereco') {
                estado.modo  = salvo;
            }
```

- [ ] **Step 11: `item.js` — `_selecionarModo` e `_bindTrocarModo` sem passo**

Substituir `_selecionarModo` por:

```js
    function _selecionarModo(modo) {
        estado.modo  = modo;
        _limparTudo();
        _salvarModo(modo);
        _renderEstado();
        _focarScannerInput();
    }
```

E, em `_bindTrocarModo`, apagar a linha `estado.passo = 0;` (mantendo `estado.modo = null;` e o resto).

- [ ] **Step 12: `item.php` — trocar o CSS do indicador de passos pelo CSS do indicador de modo**

Substituir o bloco CSS `#wms-step-indicator { ... }` até o fim de `.wms-step-sep { ... }` (as regras dos "step pills") por:

```css
    /* ===== Indicador de Modo ===== */
    #wms-modo-indicator {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 8px;
        padding: 0 1.25rem 0.75rem;
    }

    .wms-modo-atual {
        display: flex;
        align-items: baseline;
        gap: 6px;
    }

    .wms-modo-atual-rotulo {
        font-size: 0.7rem;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.06em;
        color: var(--app-texto-opaco, #64748b);
    }

    .wms-modo-atual-valor {
        font-size: 0.85rem;
        font-weight: 800;
        color: var(--app-marca-claro, #818cf8);
        letter-spacing: 0.04em;
    }
```

> Mantém o bloco `#btn-trocar-modo { ... }` (logo abaixo) intacto — ele é reutilizado.

- [ ] **Step 13: `item.php` — trocar a marcação dos "step pills" pelo indicador de modo**

Substituir o bloco de marcação `<!-- Indicador de passo --> <div id="wms-step-indicator"> ... </div>` por:

```php
            <!-- Indicador de modo -->
            <div id="wms-modo-indicator">
                <div class="wms-modo-atual">
                    <span class="wms-modo-atual-rotulo"><?= show('Bipando') ?>:</span>
                    <span class="wms-modo-atual-valor" id="wms-modo-atual-label">—</span>
                </div>
                <button type="button" id="btn-trocar-modo" title="<?= htmlspecialchars(show('Trocar modo')) ?>">
                    ↩ <?= show('Trocar modo') ?>
                </button>
            </div>
```

- [ ] **Step 14: Verificação manual no navegador**

Abrir uma missão Alocação WMS em andamento (`/missao/logistica/app/alocacaowms/{id}`) e confirmar:
1. Escolher modo **Produto** → indicador mostra "Bipando: PRODUTO"; campo Produto destacado.
2. Bipar (scanner ou digitar) → o código vai **sempre** pro campo Produto; o modo **não** muda sozinho e o foco **não** pula pra Localização.
3. Tocar no campo **Localização** → próximo bipe vai pra Localização e o destaque **volta** pra Produto.
4. Clicar **Trocar modo** → volta pra tela de escolha de modo.
5. Escolher **Endereço** → bipe vai sempre pra Localização; tocar Produto redireciona 1 bipe.
6. Após Confirmar (item conclui) e reload, o modo escolhido **permanece**.

- [ ] **Step 15: Commit (somente com autorização do usuário)**

```bash
git add componentes/Missoes/Logistica/sinais/App/html/alocacaowms/item.js \
        componentes/Missoes/Logistica/sinais/App/html/alocacaowms/item.php
git commit -m "refactor(alocacaowms): modo = campo-alvo fixo, sem inferência/auto-avanço

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"
```

---

### Task 2: Quantidade soma pelos bipes (+fator) com selo ×N + regra de produto diferente

Cada bipe do **mesmo** produto soma `+fator` à quantidade; bipar um produto **diferente** com produto já selecionado **avisa e ignora**. Um selo `×N` mostra as unidades da confirmação atual.

**Files:**
- Modify: `componentes/Missoes/Logistica/sinais/App/html/alocacaowms/item.js`
- Modify: `componentes/Missoes/Logistica/sinais/App/html/alocacaowms/item.php`

**Interfaces:**
- Consumes: `_alvoAtual`, `_selecionarItemSemAvancar`, `_buscarItemPorCodigo`, `_setProdutoCodigo`, `_setExibicaoProduto`, `_renderEstado`, `_atualizarBotaoConfirmar` (Task 1).
- Produces: `_fmtQtd(n): string`, `_atualizarBadgeUnidades(): void`; `#wms-unidades-badge` na view; `_resolverESetarProduto` agora acumula quantidade.

- [ ] **Step 1: `item.js` — helpers de quantidade**

Logo após a função `_escHtml` (seção Utilitários), adicionar:

```js
    // Formata quantidade removendo zeros decimais desnecessários (ex.: 12, 1.5).
    function _fmtQtd(n) {
        var v = Math.round((parseFloat(n) || 0) * 1000) / 1000;
        return String(v);
    }

    // Atualiza o selo "×N" de unidades acumuladas na confirmação atual.
    function _atualizarBadgeUnidades() {
        var q = parseFloat($('#wms-quantidade').val()) || 0;
        var $b = $('#wms-unidades-badge');
        if (q > 0 && (estado.produtoId || estado.produtoCodigo)) {
            $b.text('×' + _fmtQtd(q)).show();
        } else {
            $b.hide().text('');
        }
    }
```

- [ ] **Step 2: `item.js` — `_resolverESetarProduto` com contagem + regra de produto diferente**

Substituir a função `_resolverESetarProduto` (versão da Task 1) por:

```js
    function _resolverESetarProduto(codigo, origem) {
        var codigoNorm = String(codigo).trim().toUpperCase();
        var registro   = codigosBarrasMap[codigo] || codigosBarrasMap[codigoNorm];

        var novoProdutoId = registro ? parseInt(registro.produto_id, 10) : 0;
        var fator = (registro && registro.fator > 0) ? parseFloat(registro.fator) : 1;

        // Já existe um produto selecionado nesta confirmação?
        if (estado.produtoId) {
            // (a) Mesmo produto → soma a quantidade
            if (novoProdutoId && novoProdutoId === estado.produtoId) {
                var atual = parseFloat($('#wms-quantidade').val()) || 0;
                estado.quantidade = atual + fator;
                $('#wms-quantidade').val(_fmtQtd(estado.quantidade));
                _atualizarBadgeUnidades();
                _atualizarBotaoConfirmar();
                return;
            }
            // (b) Produto diferente → avisa e ignora (operador usa Limpar pra trocar)
            _mostrarToast('erro', 'Confirme ou limpe o produto atual antes de bipar outro.');
            return;
        }

        // Nenhum produto selecionado → seleciona e inicia a contagem em "fator"
        if (registro) {
            estado.produtoId     = novoProdutoId;
            estado.produtoNome   = registro.nome;
            estado.produtoCodigo = codigo;
            estado.codigoProduto = registro.codigo_produto || '';
            estado.produtoOrigem = origem;

            var $itemEl = $('#lista-itens-pendentes .wms-item-card[data-item-id="' + registro.item_id + '"]').first();
            if ($itemEl.length) {
                _selecionarItemSemAvancar($itemEl[0]);
            } else {
                _setExibicaoProduto(registro.nome, registro.codigo_produto || '');
                $('#campo-produto').addClass('preenchido').removeClass('ativo erro-campo');
            }
        } else {
            var encontrado = _buscarItemPorCodigo(codigo);
            if (encontrado) {
                _selecionarItemSemAvancar(encontrado);
                estado.produtoOrigem = origem;
            } else {
                _setProdutoCodigo(codigo, origem);
            }
        }

        estado.campoAtivo  = null;
        estado.quantidade  = fator;
        $('#wms-quantidade').val(_fmtQtd(fator));
        _atualizarBadgeUnidades();
        _renderEstado();
        _atualizarBotaoConfirmar();
    }
```

- [ ] **Step 3: `item.js` — `_limparProduto` limpa a quantidade e o selo**

Na função `_limparProduto`, logo antes da linha final `_atualizarBotaoConfirmar();`, inserir:

```js
        $('#wms-quantidade').val('');
        _atualizarBadgeUnidades();
```

- [ ] **Step 4: `item.js` — quantidade digitada à mão atualiza o selo**

Em `_bindConfirmar`, substituir o handler do input de quantidade:

```js
        $('#wms-quantidade').on('input', function () { _atualizarBotaoConfirmar(); });
```

por:

```js
        $('#wms-quantidade').on('input', function () {
            estado.quantidade = parseFloat($(this).val()) || null;
            _atualizarBadgeUnidades();
            _atualizarBotaoConfirmar();
        });
```

- [ ] **Step 5: `item.js` — seleção pela lista inicia contagem zerada**

Na função `_selecionarItemPorElemento`, substituir o final:

```js
        // Rola até o campo de localização
        setTimeout(function () {
            $('#campo-localizacao')[0].scrollIntoView({ behavior: 'smooth', block: 'center' });
        }, 150);

        _renderEstado();
        _atualizarBotaoConfirmar();
    }
```

por:

```js
        // Rola até o campo de localização
        setTimeout(function () {
            $('#campo-localizacao')[0].scrollIntoView({ behavior: 'smooth', block: 'center' });
        }, 150);

        // Seleção pela lista inicia contagem zerada (qty vem dos bipes ou da digitação)
        $('#wms-quantidade').val('');
        estado.quantidade = null;
        _atualizarBadgeUnidades();
        _renderEstado();
        _atualizarBotaoConfirmar();
    }
```

- [ ] **Step 6: `item.js` — digitação manual do produto passa a contar (mesma lógica do bipe)**

Em `_bindInputManuais`, centralizar o produto digitado em `_resolverESetarProduto`. Substituir o handler de keydown do produto:

```js
        $('#input-manual-produto').on('keydown', function (e) {
            if (e.key === 'Enter') {
                var codigo = $(this).val().trim();
                if (codigo) {
                    var encontrado = _buscarItemPorCodigo(codigo);
                    if (encontrado) {
                        estado.produtoOrigem = 'manual';
                        _selecionarItemPorElemento(encontrado);
                    } else {
                        _setProdutoCodigo(codigo, 'manual');
                    }
                    $(this).hide().val('');
                    _focarScannerInput();
                }
                e.preventDefault();
            }
        });
```

por:

```js
        $('#input-manual-produto').on('keydown', function (e) {
            if (e.key === 'Enter') {
                var codigo = $(this).val().trim();
                if (codigo) {
                    _resolverESetarProduto(codigo, 'manual');
                    $(this).hide().val('');
                    _focarScannerInput();
                }
                e.preventDefault();
            }
        });
```

E substituir o handler de `blur` (produto + localização):

```js
        // Confirmar com toque/blur no mobile
        $('#input-manual-produto, #input-manual-localizacao').on('blur', function () {
            var tipo  = $(this).is('#input-manual-produto') ? 'produto' : 'localizacao';
            var codigo = $(this).val().trim();
            if (codigo) {
                if (tipo === 'produto') {
                    var encontrado = _buscarItemPorCodigo(codigo);
                    if (encontrado) {
                        estado.produtoOrigem = 'manual';
                        _selecionarItemPorElemento(encontrado);
                    } else {
                        _setProdutoCodigo(codigo, 'manual');
                    }
                } else {
                    _setLocalizacao(codigo, 'manual');
                }
                $(this).hide().val('');
            }
        });
```

por:

```js
        // Confirmar com toque/blur no mobile
        $('#input-manual-produto, #input-manual-localizacao').on('blur', function () {
            var tipo  = $(this).is('#input-manual-produto') ? 'produto' : 'localizacao';
            var codigo = $(this).val().trim();
            if (codigo) {
                if (tipo === 'produto') {
                    _resolverESetarProduto(codigo, 'manual');
                } else {
                    _setLocalizacao(codigo, 'manual');
                }
                $(this).hide().val('');
            }
        });
```

- [ ] **Step 7: `item.php` — adicionar o selo de unidades no campo Produto**

No campo Produto, na linha do rótulo, substituir:

```php
                        <div class="wms-scan-label"><?= show('Produto') ?></div>
```

por:

```php
                        <div class="wms-scan-label">
                            <?= show('Produto') ?>
                            <span id="wms-unidades-badge" class="wms-unidades-badge" style="display:none;"></span>
                        </div>
```

- [ ] **Step 8: `item.php` — CSS do selo de unidades**

No bloco `<style>`, logo após as regras de `.wms-scan-label`, adicionar:

```css
    .wms-unidades-badge {
        display: inline-block;
        margin-left: 6px;
        background: rgba(79, 70, 229, 0.2);
        color: var(--app-marca-claro, #818cf8);
        border-radius: 20px;
        padding: 1px 8px;
        font-size: 0.72rem;
        font-weight: 800;
        font-family: 'JetBrains Mono', monospace;
        vertical-align: middle;
    }
```

- [ ] **Step 9: Verificação manual no navegador**

Numa missão em andamento, modo **Produto**:
1. Bipar o mesmo produto 3× → Quantidade mostra a soma dos fatores (ex.: fator 1 → "3"; fator 12 → "36"); selo `×N` acompanha.
2. Editar a Quantidade à mão → selo atualiza; valor é aceito no Confirmar.
3. Selecionar produto pela **lista** (toque) → Quantidade começa **vazia**; bipar o mesmo produto soma a partir do fator.
4. Com produto selecionado, bipar um produto **diferente** → toast "Confirme ou limpe o produto atual…" e a contagem atual **não muda**.
5. Clicar **Limpar** (✕) no produto → Quantidade e selo zeram.
6. Preencher Localização e **Confirmar** → grava normal e marca item `concluído` (verificar no banco/lista que a `quantidade` salva = soma bipada).

- [ ] **Step 10: Commit (somente com autorização do usuário)**

```bash
git add componentes/Missoes/Logistica/sinais/App/html/alocacaowms/item.js \
        componentes/Missoes/Logistica/sinais/App/html/alocacaowms/item.php
git commit -m "feat(alocacaowms): contagem por bipe (+fator) com selo de unidades e regra de produto diferente

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"
```

---

### Task 3: i18n (3 idiomas) + regressão manual completa

Garante que os textos novos da view existem nos 3 idiomas e roda o checklist de regressão completo do spec §9.

**Files:**
- Modify (se necessário): `linguagens/pt-br.json`, `linguagens/en.json`, `linguagens/es.json`

**Interfaces:**
- Consumes: strings de `show()` adicionadas nas Tasks 1–2 ("Bipando", "Trocar modo").

- [ ] **Step 1: Disparar o auto-harvest abrindo a tela**

Abrir a tela da missão no navegador (renderiza os `show()` novos). Os textos PT são coletados automaticamente (auto-harvest do galaxia i18n).

- [ ] **Step 2: Conferir as traduções EN/ES**

Verificar nos arquivos de idioma se as chaves dos textos novos ("Bipando", "Trocar modo") têm tradução em `en.json` e `es.json`. Se estiverem vazias/ausentes, preencher manualmente (a chave é o md5 do texto PT). Exemplo de conferência:

Run: `grep -ri "bipando\|trocar modo" linguagens/`
Expected: a chave existe nos 3 arquivos com valores PT/EN/ES (ex.: "Bipando"/"Scanning"/"Escaneando"; "Trocar modo"/"Change mode"/"Cambiar modo").

- [ ] **Step 3: Validar i18n no navegador**

Trocar o idioma da sessão (ou setor) e confirmar que o indicador de modo aparece traduzido.

- [ ] **Step 4: Regressão manual completa (spec §9)**

Confirmar, numa missão real:
1. Modo escolhido **gruda** (não muda sozinho após bipe nem após Confirmar/reload).
2. Bipe **nunca** vai pro campo errado (modo Produto só preenche Produto; modo Endereço só Localização).
3. Toque em campo oposto redireciona **1 bipe** e volta.
4. Quantidade **soma** a cada bipe do mesmo produto (`+fator`); editável à mão.
5. Produto diferente → **toast + ignora**.
6. **Confirmar** grava e marca item `concluído`; a `quantidade` persistida bate com a contagem.

- [ ] **Step 5: Commit (somente com autorização do usuário)**

```bash
git add linguagens/pt-br.json linguagens/en.json linguagens/es.json
git commit -m "i18n(alocacaowms): textos do indicador de modo (pt/en/es)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"
```

---

## Notas de execução

- **Ordem:** Task 1 → Task 2 → Task 3. A Task 2 depende dos renomes/remoções da Task 1.
- **Risco de churn:** `_resolverESetarProduto` é editada na Task 1 (remoção de avanço) e reescrita na Task 2 (contagem). Se executar as duas juntas, pode pular direto pra versão final da Task 2.
- **Rollback:** como é só `item.js`/`item.php` (e idiomas), reverter é um `git checkout` desses arquivos.
