# EdicaoRota — Observação do Operador para o Motorista

> **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:** Permitir que o operador deixe uma observação ao liberar a rota; o motorista vê o texto como um card entre "Planejamento da Rota" e "Sequência de entrega".

**Architecture:** Nova coluna `observacao_operador VARCHAR(500) NULL` em `edicoes_rota`. O operador preenche via sub-modal (sobreposto ao modal de liberação) em `central.php`; o campo vai no payload `POST /api/v1/edicao-rota` e é salvo por `CriarEdicaoRotaLaboratorio`. A view `editar_rota.php` renderiza o card condicionalmente quando o campo não é nulo.

**Tech Stack:** PHP (Sonda V2 / ModelInteligencia), SQL (MySQL), JavaScript (jQuery + Fetch), Tailwind CSS (modal operador), CSS custom (view motorista)

---

## Mapa de arquivos

| Arquivo | Ação |
|---|---|
| `Migrations/005_observacao_operador.sql` | **Criar** — DDL da nova coluna |
| `Validators/CriarEdicaoRotaValidator.php` | **Editar** — validação opcional do campo (max 500) |
| `Testes/Laboratorios/CriarEdicaoRotaLaboratorioTddTest.php` | **Editar** — adicionar casos de teste para obs |
| `Laboratorios/CriarEdicaoRotaLaboratorio.php` | **Editar** — salvar campo no payload |
| `Edicaorota.php` | **Editar** — passar `observacao_operador` para a view |
| `html/_layout.php` | **Editar** — CSS do card de observação |
| `html/editar_rota.php` | **Editar** — card HTML + variável PHP |
| `Central/html/central.php` | **Editar** — botão ícone, sub-modal HTML+CSS, JS state+payload |

Todos os caminhos são relativos a `componentes/Missoes/Logistica/sinais/Edicaorota/`
exceto `Central/html/central.php` que é `componentes/Missoes/Logistica/sinais/Central/html/central.php`.

---

### Task 1: Migration — adicionar coluna `observacao_operador`

**Files:**
- Create: `componentes/Missoes/Logistica/sinais/Edicaorota/Migrations/005_observacao_operador.sql`

- [ ] **Criar o arquivo de migration**

```sql
-- Migration 005: adiciona observacao_operador na tabela edicoes_rota.
-- Campo nullable (observação é opcional).
ALTER TABLE edicoes_rota
  ADD COLUMN observacao_operador VARCHAR(500) NULL;
```

- [ ] **Aplicar no banco de desenvolvimento**

```bash
cd /home/goldie/www/genesis
mysql -u root gx_goldie < componentes/Missoes/Logistica/sinais/Edicaorota/Migrations/005_observacao_operador.sql
```

Esperado: comando sem erros. Verificar:
```bash
mysql -u root gx_goldie -e "SHOW COLUMNS FROM edicoes_rota LIKE 'observacao_operador';"
```
Esperado: linha com `observacao_operador | varchar(500) | YES | ...`

- [ ] **Commit**

```bash
cd /home/goldie/www/genesis
git add componentes/Missoes/Logistica/sinais/Edicaorota/Migrations/005_observacao_operador.sql
git commit -m "feat(edicaorota): add observacao_operador column to edicoes_rota"
```

---

### Task 2: Validator — validar `observacao_operador` (TDD)

**Files:**
- Modify: `componentes/Missoes/Logistica/sinais/Edicaorota/Validators/CriarEdicaoRotaValidator.php`
- Modify: `componentes/Missoes/Logistica/sinais/Edicaorota/Testes/Laboratorios/CriarEdicaoRotaLaboratorioTddTest.php`

- [ ] **Adicionar casos de teste no TDD existente**

Abrir `Testes/Laboratorios/CriarEdicaoRotaLaboratorioTddTest.php`.
Após o bloco `// --- Registry ---` (antes da linha `echo "\n===..."`), inserir:

```php
// --- observacao_operador ---
EdicaoRotaCallbackRegistry::reset();
EdicaoRotaCallbackRegistry::registrar('teste_fake', FakeCallback::class);

$base = [
    'callback_modulo'        => 'teste_fake',
    'callback_referencia_id' => 1,
    'telefone_motorista'     => '11999999999',
    'rota_atual'             => [['id' => 1]],
];

$err5 = $validator->validar($base);
AssertCriar::true(
    empty($err5),
    'Validator aceita payload sem observacao_operador'
);

$err6 = $validator->validar(array_merge($base, ['observacao_operador' => '']));
AssertCriar::true(
    empty($err6),
    'Validator aceita observacao_operador vazia (string vazia = ausente)'
);

$err7 = $validator->validar(array_merge($base, ['observacao_operador' => str_repeat('a', 500)]));
AssertCriar::true(
    empty($err7),
    'Validator aceita observacao_operador com exatamente 500 caracteres'
);

$err8 = $validator->validar(array_merge($base, ['observacao_operador' => str_repeat('a', 501)]));
AssertCriar::true(
    !empty($err8) && (bool) array_filter($err8, fn($e) => str_contains($e, 'observa')),
    'Validator rejeita observacao_operador com 501 caracteres'
);
```

- [ ] **Rodar o teste — confirmar falha no caso de 501 chars**

```bash
cd /home/goldie/www/genesis/componentes/Missoes/Logistica/sinais/Edicaorota
php Testes/Laboratorios/CriarEdicaoRotaLaboratorioTddTest.php 2>&1
```

Esperado: os 3 primeiros casos passam, o 4º (`501 caracteres`) **falha** com `❌ [FAIL]`.

- [ ] **Implementar validação em `CriarEdicaoRotaValidator.php`**

No método `validar()`, após a última verificação (`rota_atual`), adicionar:

```php
if (!empty($entrada['observacao_operador'])) {
    if (mb_strlen((string) $entrada['observacao_operador']) > 500) {
        $erros[] = 'observacao_operador não pode ultrapassar 500 caracteres.';
    }
}
```

- [ ] **Rodar o teste — confirmar que todos passam**

```bash
cd /home/goldie/www/genesis/componentes/Missoes/Logistica/sinais/Edicaorota
php Testes/Laboratorios/CriarEdicaoRotaLaboratorioTddTest.php 2>&1
```

Esperado: `✅` em todos os casos, `TODOS OS TESTES PASSARAM`.

- [ ] **Commit**

```bash
cd /home/goldie/www/genesis
git add componentes/Missoes/Logistica/sinais/Edicaorota/Validators/CriarEdicaoRotaValidator.php \
        componentes/Missoes/Logistica/sinais/Edicaorota/Testes/Laboratorios/CriarEdicaoRotaLaboratorioTddTest.php
git commit -m "feat(edicaorota): validate observacao_operador max 500 chars"
```

---

### Task 3: Laboratório — salvar `observacao_operador`

**Files:**
- Modify: `componentes/Missoes/Logistica/sinais/Edicaorota/Laboratorios/CriarEdicaoRotaLaboratorio.php`

- [ ] **Adicionar processamento do campo após `$dataPartida` (linha ~74)**

No método `executar()`, após o bloco `if ($dataPartida !== '') ...` e antes do `$sonda = new EdicaoRotaSonda();`, adicionar:

```php
$obsOp = '';
if (!empty($entrada['observacao_operador'])) {
    $obsOp = mb_substr(trim((string) $entrada['observacao_operador']), 0, 500);
}
```

Depois, no bloco de montagem do `$payload` (após `if ($dataPartida !== '')  $payload['data_partida']      = $dataPartida;`), adicionar:

```php
if ($obsOp !== '') $payload['observacao_operador'] = $obsOp;
```

O trecho final do bloco de payload deve ficar assim:

```php
if ($endPartida !== '')   $payload['endereco_partida']      = $endPartida;
if ($latPartida !== null) $payload['latitude_partida']      = $latPartida;
if ($lngPartida !== null) $payload['longitude_partida']     = $lngPartida;
if ($horaPartida !== '')  $payload['horario_partida']       = $horaPartida;
if ($dataPartida !== '')  $payload['data_partida']          = $dataPartida;
if ($obsOp !== '')        $payload['observacao_operador']   = $obsOp;
$sonda->make($payload);
```

- [ ] **Verificar sintaxe**

```bash
cd /home/goldie/www/genesis
php -l componentes/Missoes/Logistica/sinais/Edicaorota/Laboratorios/CriarEdicaoRotaLaboratorio.php
```

Esperado: `No syntax errors detected`

- [ ] **Commit**

```bash
cd /home/goldie/www/genesis
git add componentes/Missoes/Logistica/sinais/Edicaorota/Laboratorios/CriarEdicaoRotaLaboratorio.php
git commit -m "feat(edicaorota): save observacao_operador in CriarEdicaoRotaLaboratorio"
```

---

### Task 4: Controller — passar `observacao_operador` para a view

**Files:**
- Modify: `componentes/Missoes/Logistica/sinais/Edicaorota/Edicaorota.php`

- [ ] **Adicionar o campo no array passado para `renderMotorista`**

No método `telaMotorista()`, localizar o bloco `return $this->renderMotorista('html/editar_rota', [` (linha ~293).

O array atual termina com:
```php
'expira_em'      => isset($edicao->expira_em) ? (string) $edicao->expira_em : null,
```

Adicionar uma linha após essa:
```php
'observacao_operador' => isset($edicao->observacao_operador) && $edicao->observacao_operador !== ''
    ? (string) $edicao->observacao_operador
    : null,
```

- [ ] **Verificar sintaxe**

```bash
cd /home/goldie/www/genesis
php -l componentes/Missoes/Logistica/sinais/Edicaorota/Edicaorota.php
```

Esperado: `No syntax errors detected`

- [ ] **Commit**

```bash
cd /home/goldie/www/genesis
git add componentes/Missoes/Logistica/sinais/Edicaorota/Edicaorota.php
git commit -m "feat(edicaorota): pass observacao_operador to editar_rota view"
```

---

### Task 5: CSS do card de observação na view do motorista

**Files:**
- Modify: `componentes/Missoes/Logistica/sinais/Edicaorota/html/_layout.php`

- [ ] **Adicionar CSS ao final do bloco `<style>` em `_layout.php`**

Localizar o fechamento `</style>` antes de `</head>` (próximo à linha 1442). Inserir antes de `</style>`:

```css
  /* Card de observação do operador — borda âmbar p/ distinguir dos outros cards */
  .obs-operador-card {
    border-color: rgba(251, 191, 36, 0.35);
    background: linear-gradient(145deg, rgba(30, 25, 60, 0.85) 0%, rgba(38, 32, 75, 0.78) 100%);
  }
  .obs-operador-texto {
    margin: 0;
    color: var(--text);
    font-size: 0.95rem;
    line-height: 1.55;
    white-space: pre-wrap;
    word-break: break-word;
  }
```

- [ ] **Verificar sintaxe**

```bash
cd /home/goldie/www/genesis
php -l componentes/Missoes/Logistica/sinais/Edicaorota/html/_layout.php
```

Esperado: `No syntax errors detected`

- [ ] **Commit**

```bash
cd /home/goldie/www/genesis
git add componentes/Missoes/Logistica/sinais/Edicaorota/html/_layout.php
git commit -m "feat(edicaorota): add CSS for obs-operador card in driver layout"
```

---

### Task 6: Card HTML na view do motorista

**Files:**
- Modify: `componentes/Missoes/Logistica/sinais/Edicaorota/html/editar_rota.php`

- [ ] **Adicionar variável PHP no topo**

Localizar o bloco de inicialização de variáveis no topo do arquivo (após linha 19, `$expiraEm = ...`).
Adicionar logo após:

```php
$observacaoOperador = !empty($observacao_operador) ? (string) $observacao_operador : null;
```

- [ ] **Inserir card entre "Planejamento da Rota" e "Sequência de entrega"**

Localizar a linha que fecha o card de planejamento (linha ~181):
```php
    <?php endif; ?>
```
(essa é a linha imediatamente antes de `<div class="card">` que abre "Sequência de entrega")

Inserir após esse `<?php endif; ?>`:

```php
    <?php if ($observacaoOperador !== null): ?>
    <div class="card obs-operador-card">
      <div class="card-secao-label">
        <i class="card-secao-icone" aria-hidden="true">📝</i>
        <span class="card-secao-texto">Observação do operador</span>
      </div>
      <p class="obs-operador-texto"><?= nl2br(htmlspecialchars($observacaoOperador)) ?></p>
    </div>
    <?php endif; ?>
```

Para encontrar o ponto exato de inserção, o contexto ao redor é:
```php
    </div>
    <?php endif; ?>

    <div class="card">
      <div class="card-secao-label">
        <i class="card-secao-icone" aria-hidden="true">📋</i>
        <span class="card-secao-texto">Sequência de entrega</span>
```

O card novo vai entre o `<?php endif; ?>` (que fecha o bloco do resumo) e o `<div class="card">` da sequência.

- [ ] **Verificar sintaxe**

```bash
cd /home/goldie/www/genesis
php -l componentes/Missoes/Logistica/sinais/Edicaorota/html/editar_rota.php
```

Esperado: `No syntax errors detected`

- [ ] **Commit**

```bash
cd /home/goldie/www/genesis
git add componentes/Missoes/Logistica/sinais/Edicaorota/html/editar_rota.php
git commit -m "feat(edicaorota): show observacao_operador card in driver route edit view"
```

---

### Task 7: Sub-modal HTML + CSS em `central.php`

**Files:**
- Modify: `componentes/Missoes/Logistica/sinais/Central/html/central.php`

**Parte A — ícone no header do modal de liberação**

- [ ] **Adicionar botão de bloco de notas no header**

Localizar a linha (≈2683–2685):
```html
        <div class="g-liberar-modal-header">
            <h3 class="g-liberar-modal-title"><i class="fas fa-paper-plane"></i>Liberar rota para motorista</h3>
            <button id="liberar-motorista-fechar" class="g-liberar-modal-close" type="button" aria-label="Fechar">&times;</button>
        </div>
```

Substituir por:
```html
        <div class="g-liberar-modal-header">
            <h3 class="g-liberar-modal-title"><i class="fas fa-paper-plane"></i>Liberar rota para motorista</h3>
            <div class="g-liberar-modal-header-acoes">
                <button id="liberar-motorista-obs-btn"
                        class="g-liberar-obs-btn"
                        type="button"
                        title="Adicionar observação para o motorista"
                        aria-label="Observação para o motorista">
                    <i class="fas fa-sticky-note"></i>
                </button>
                <button id="liberar-motorista-fechar" class="g-liberar-modal-close" type="button" aria-label="Fechar">&times;</button>
            </div>
        </div>
```

**Parte B — sub-modal HTML**

- [ ] **Adicionar sub-modal após o fechamento do `#liberar-motorista-modal`**

Localizar (≈linha 2733):
```html
</div>
```
(a linha que fecha o `#liberar-motorista-modal`)

Inserir imediatamente após:

```html
<!-- Sub-modal: Observação do operador para o motorista -->
<div id="liberar-obs-modal" class="g-liberar-obs-overlay hidden fixed inset-0 z-[60] flex items-center justify-center bg-black/60 backdrop-blur-sm">
    <div class="g-liberar-obs-card w-full max-w-md text-white">
        <div class="g-liberar-obs-header">
            <h4 class="g-liberar-obs-titulo"><i class="fas fa-sticky-note"></i>Observação para o motorista</h4>
        </div>
        <div class="p-4 space-y-3">
            <textarea id="liberar-obs-textarea"
                      class="g-liberar-obs-textarea w-full"
                      rows="5"
                      maxlength="500"
                      placeholder="Digite uma observação para o motorista..."></textarea>
            <div id="liberar-obs-contador" class="text-right text-xs text-gray-400">500 restantes</div>
        </div>
        <div class="g-liberar-obs-footer flex justify-end gap-2 p-4">
            <button id="liberar-obs-cancelar" class="g-botao g-botao-contorno" type="button">Cancelar</button>
            <button id="liberar-obs-salvar" class="g-botao g-botao-solido-marca" type="button">
                <i class="fas fa-check mr-2"></i>Salvar
            </button>
        </div>
    </div>
</div>
```

**Parte C — CSS**

- [ ] **Adicionar CSS no bloco `<style>` existente do modal de liberação (≈linha 2835)**

Localizar o final do bloco `<style>` do modal de liberação (procurar `</style>` logo após as regras `.g-liberar-modal-*`). Inserir antes desse `</style>`:

```css
    /* Header: flex para alinhar título + ações (ícone obs + fechar) */
    .g-liberar-modal-header-acoes {
        display: flex;
        align-items: center;
        gap: 4px;
        margin-left: auto;
    }

    /* Botão de observação — ícone discreto, fica âmbar quando há texto salvo */
    .g-liberar-obs-btn {
        background: transparent;
        border: 1px solid transparent;
        border-radius: 0.5rem;
        color: rgba(255, 255, 255, 0.45);
        font-size: 1.1rem;
        padding: 0.4rem 0.5rem;
        cursor: pointer;
        transition: color 0.2s, border-color 0.2s, background 0.2s;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
    .g-liberar-obs-btn:hover {
        color: #fbbf24;
        border-color: rgba(251, 191, 36, 0.4);
        background: rgba(251, 191, 36, 0.08);
    }
    .g-liberar-obs-btn.com-obs {
        color: #fbbf24;
        border-color: rgba(251, 191, 36, 0.5);
        background: rgba(251, 191, 36, 0.1);
    }

    /* Sub-modal card */
    .g-liberar-obs-card {
        background: linear-gradient(145deg, rgba(15, 12, 41, 0.99) 0%, rgba(26, 20, 53, 0.99) 100%);
        backdrop-filter: blur(12px);
        border: 1px solid rgba(251, 191, 36, 0.3);
        border-radius: 1.25rem;
        box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6), 0 0 40px rgba(251, 191, 36, 0.06);
        overflow: hidden;
    }
    .g-liberar-obs-header {
        padding: 1rem 1.5rem 0.55rem;
        border-bottom: 1px solid rgba(251, 191, 36, 0.18);
    }
    .g-liberar-obs-titulo {
        margin: 0;
        font-size: 1.1rem;
        font-weight: 700;
        color: #ffffff;
        display: flex;
        align-items: center;
        gap: 0.5rem;
    }
    .g-liberar-obs-titulo i { color: #fbbf24; }
    .g-liberar-obs-footer {
        border-top: 1px solid rgba(139, 92, 246, 0.15);
    }
    .g-liberar-obs-textarea {
        background: rgba(15, 12, 41, 0.6);
        border: 1px solid rgba(139, 92, 246, 0.3);
        border-radius: 0.625rem;
        color: #f1f5f9;
        font-size: 0.95rem;
        line-height: 1.5;
        padding: 10px 12px;
        resize: vertical;
        min-height: 100px;
        transition: border-color 0.2s, box-shadow 0.2s;
    }
    .g-liberar-obs-textarea::placeholder { color: rgba(196, 181, 253, 0.4); }
    .g-liberar-obs-textarea:focus {
        outline: none;
        border-color: #fbbf24;
        box-shadow: 0 0 0 3px rgba(251, 191, 36, 0.15);
    }
```

- [ ] **Verificar sintaxe PHP**

```bash
cd /home/goldie/www/genesis
php -l componentes/Missoes/Logistica/sinais/Central/html/central.php
```

Esperado: `No syntax errors detected`

- [ ] **Commit**

```bash
cd /home/goldie/www/genesis
git add componentes/Missoes/Logistica/sinais/Central/html/central.php
git commit -m "feat(edicaorota): add observation sub-modal HTML and CSS to liberation modal"
```

---

### Task 8: JS — estado, sub-modal e payload em `central.php`

**Files:**
- Modify: `componentes/Missoes/Logistica/sinais/Central/html/central.php`

**Parte A — variável de estado**

- [ ] **Adicionar `liberarMotoristaObservacao` junto com as outras variáveis de estado**

Localizar (≈linha 4543):
```js
    let liberarMotoristaIti = null;
    let enviadoExibirTela = false;
```

Adicionar logo após:
```js
    let liberarMotoristaObservacao = '';
```

**Parte B — resetar observação ao abrir e ao fechar modal**

- [ ] **Resetar no handler de abertura do modal**

Localizar (≈linha 5027):
```js
        enviadoExibirTela = false;
        resetBotaoLiberar();
```

Adicionar logo após `resetBotaoLiberar();`:
```js
        liberarMotoristaObservacao = '';
        $('#liberar-motorista-obs-btn').removeClass('com-obs');
```

- [ ] **Resetar no handler de fechar/cancelar**

Localizar (≈linha 5038):
```js
    $(document).on('click', '#liberar-motorista-fechar, #liberar-motorista-cancelar', function () {
        $('#liberar-motorista-modal').addClass('hidden');
        enviadoExibirTela = false;
        resetBotaoLiberar();
    });
```

Substituir por:
```js
    $(document).on('click', '#liberar-motorista-fechar, #liberar-motorista-cancelar', function () {
        $('#liberar-motorista-modal').addClass('hidden');
        enviadoExibirTela = false;
        liberarMotoristaObservacao = '';
        $('#liberar-motorista-obs-btn').removeClass('com-obs');
        resetBotaoLiberar();
    });
```

**Parte C — handlers do sub-modal**

- [ ] **Adicionar handlers do sub-modal após o handler de fechar (após linha ~5042)**

Inserir após o handler `#liberar-motorista-fechar, #liberar-motorista-cancelar`:

```js
    // ----- Sub-modal de observação -----
    function atualizarContadorObs() {
        const len = ($('#liberar-obs-textarea').val() || '').length;
        $('#liberar-obs-contador').text((500 - len) + ' restantes');
    }

    $(document).on('click', '#liberar-motorista-obs-btn', function () {
        $('#liberar-obs-textarea').val(liberarMotoristaObservacao);
        atualizarContadorObs();
        $('#liberar-obs-modal').removeClass('hidden');
        setTimeout(() => $('#liberar-obs-textarea').focus(), 50);
    });

    $(document).on('input', '#liberar-obs-textarea', atualizarContadorObs);

    $(document).on('click', '#liberar-obs-cancelar', function () {
        $('#liberar-obs-modal').addClass('hidden');
    });

    $(document).on('click', '#liberar-obs-salvar', function () {
        const val = ($('#liberar-obs-textarea').val() || '').trim().substring(0, 500);
        liberarMotoristaObservacao = val;
        $('#liberar-motorista-obs-btn').toggleClass('com-obs', val !== '');
        $('#liberar-obs-modal').addClass('hidden');
    });
```

**Parte D — incluir `observacao_operador` no payload da API**

- [ ] **Adicionar campo ao body antes da chamada `api('POST', '/api/v1/edicao-rota', body)`**

Localizar (≈linha 5165):
```js
            if (partidaSnap) Object.assign(body, partidaSnap);
            const criar = await api('POST', '/api/v1/edicao-rota', body);
```

Substituir por:
```js
            if (partidaSnap) Object.assign(body, partidaSnap);
            if (liberarMotoristaObservacao.trim()) {
                body.observacao_operador = liberarMotoristaObservacao.trim();
            }
            const criar = await api('POST', '/api/v1/edicao-rota', body);
```

- [ ] **Verificar sintaxe PHP**

```bash
cd /home/goldie/www/genesis
php -l componentes/Missoes/Logistica/sinais/Central/html/central.php
```

Esperado: `No syntax errors detected`

- [ ] **Commit**

```bash
cd /home/goldie/www/genesis
git add componentes/Missoes/Logistica/sinais/Central/html/central.php
git commit -m "feat(edicaorota): JS state and payload for observacao_operador in liberation modal"
```

---

## Self-Review

### 1. Cobertura da spec

| Requisito da spec | Task |
|---|---|
| Migration `observacao_operador VARCHAR(500) NULL` | Task 1 |
| Validação max 500 chars no Validator | Task 2 |
| Laboratório salva o campo | Task 3 |
| Controller passa campo para view | Task 4 |
| CSS do card no motorista | Task 5 |
| Card HTML entre "Planejamento da Rota" e "Sequência de entrega" | Task 6 |
| Ícone de bloco de notas no modal de liberação | Task 7 |
| Sub-modal HTML + CSS com textarea e contador | Task 7 |
| JS: abrir sub-modal pré-preenchido | Task 8 |
| JS: salvar texto em memória, ícone âmbar | Task 8 |
| JS: resetar ao fechar modal de liberação | Task 8 |
| JS: enviar `observacao_operador` no payload | Task 8 |
| Observação persiste no reenvio (já salva na criação) | coberto implicitamente — reenvio não modifica o registro |

### 2. Consistência de tipos/nomes

- `liberarMotoristaObservacao` — declarada em Task 8A, usada em 8B, 8C, 8D. ✅
- `#liberar-obs-modal`, `#liberar-obs-textarea`, `#liberar-obs-contador`, `#liberar-obs-salvar`, `#liberar-obs-cancelar` — definidos em Task 7B, referenciados em Task 8C. ✅
- `#liberar-motorista-obs-btn` — definido em Task 7A, referenciado em 8B e 8C. ✅
- `obs-operador-card`, `obs-operador-texto` — CSS em Task 5, HTML em Task 6. ✅
- `observacao_operador` — coluna (Task 1), validator (Task 2), lab (Task 3), controller (Task 4), view (Task 6). ✅
