# UI — Portal e questionário (estilo game)

Documento de referência do lote **visual/UX** no portal do participante e na experiência game (splash, hub, botões). Complementa [deploy-producao-questionario-experiencia.md](./deploy-producao-questionario-experiencia.md) (fluxo e regras de negócio).

**Última atualização:** 2026-05-27 (regra de negócio do ranking documentada; ver [correcao-ranking-portal-escopo-2026-05-27.md](./correcao-ranking-portal-escopo-2026-05-27.md)).

Documentação complementar deste lote: [lote-ui-login-jogar-resultado-2026-05-19.md](./lote-ui-login-jogar-resultado-2026-05-19.md).

---

## 1. Resumo do produto

| Área | O que mudou |
|------|-------------|
| **Shell do portal** | Sidebar e topbar com cor primária do tema, gradiente na área da logo, ícones alinhados ao tom “game”. |
| **Login** (`/login`) | Logo e favicon do cadastro; fundo gradiente game (single-tenant); botão com cor primária. Ver [§8](#8-login-branding). |
| **Hub do questionário** (`/portal/questionario`) | Card escuro estilo game; layout em coluna (setor → grupo → datas); CSS dedicado sem carregar o bundle completo do jogo. |
| **Botão dourado 3D** | Estilo unificado em `game-start-button.css`; fino no hub; gordinho na splash, pausa, confirmar, voltar e modais. |
| **Splash** (`/portal/questionario/experiencia`) | Triângulos wireframe em **SVG** (grandes, espaçados); wrapper mobile no botão INICIAR. |
| **Jogar** | Dois blocos (pergunta / alternativas), barra de progresso, relógio no HUD, confirmar 3D. Ver [§9](#9-tela-de-jogar). |
| **Modais** | Acerto (verde + partículas) e **erro** (vermelho); avanço só no botão. Ver [§10](#10-modais-acerto-e-erro). |
| **Resultado** | Resumo + pódio/ranking top 10 (sem lista por pergunta). Ver [§11](#11-tela-de-resultado). |
| **Tipografia game** | **Cinzel** (Google Fonts, OFL) no layout `questionnaire-game`. |
| **Ranking na home** | Pódio estilo game (`battery-ranking.css`); badge **“Você”**. Ver [§12](#12-ranking-partilhado). |
| **Gestão (admin)** | Correção de overflow horizontal no dashboard em mobile (`min-w-0` em layout flex). |

---

## 2. Assets Vite

Entradas em `vite.config.js`:

| Entrada | Uso |
|---------|-----|
| `resources/css/questionnaire-game.css` | Splash, jogar, resultado (ecrã cheio). Importa `game-start-button.css` e `battery-ranking.css`. |
| `resources/css/portal-questionnaire-hub.css` | Hub/welcome do questionário. Importa `game-start-button.css` e `battery-ranking.css`. |
| `resources/css/game-start-button.css` | Botão INICIAR/Continuar/Confirmar/Voltar (hub + experiência). |
| `resources/css/battery-ranking.css` | Pódio e lista de ranking (home portal + resultado game). |

**Deploy:** `npm ci && npm run build` — `public/build/` não vai no Git.

---

## 3. Botão 3D (`game-start-button.css`)

Classes principais:

| Classe | Contexto |
|--------|----------|
| `.qhub-btn--game` | Hub — listagem do questionário (`<x-portal.game-button>`) |
| `.qg-btn-iniciar` | Splash, overlay de pausa, modal de acerto |

Comportamento:

- Gradiente dourado multicamada, brilho `::before`, moldura `::after`, asas e gemas.
- **Hub:** `padding` fino, `min-width` até 21rem.
- **Experiência:** mais alto, `clamp` no padding horizontal, `max-width` responsivo; wrapper `.qg-splash__btn-wrap` no splash.
- **Hover:** sutil (`brightness(1.02)`, sombra quase igual ao repouso), só com `@media (hover: hover)`.
- **Pulse:** animação `game-start-btn-pulse` na sombra (estado normal).

Componente Blade: `resources/views/components/portal/game-button.blade.php`.

---

## 4. Triângulos wireframe no splash

Substituição da malha CSS (grade contínua) por **SVG com polígonos soltos**.

| Artefato | Função |
|----------|--------|
| `resources/views/components/questionnaire/splash-wire-corner.blade.php` | Componente `<x-questionnaire.splash-wire-corner corner="tl\|br" />` |
| `experience-splash.blade.php` | Dois cantos: `tl` e `br` (este com `rotate(180deg)` no container) |

Grupos no SVG (viewBox `0 0 800 800`):

- **`--near`** — 3 triângulos grandes no canto (opacidade ~0,95).
- **`--mid`** — 5 triângulos a meio caminho (~0,58).
- **`--far`** — 6 triângulos espalhados / falhados (~0,30).

Máscara em gradiente para o fade em direção ao centro. Container até ~105vw / 920px (desktop).

Estilos: `.qg-splash__wires`, `.qg-splash__wire-svg`, `.qg-splash__wire-tri--*` em `questionnaire-game.css`.

---

## 5. Ficheiros por pasta

Ver inventário completo em [lote-ui-login-jogar-resultado-2026-05-19.md §6](./lote-ui-login-jogar-resultado-2026-05-19.md#6-inventário-de-ficheiros).

### Criados (lote completo UI game)

- `resources/css/game-start-button.css`
- `resources/css/portal-questionnaire-hub.css`
- `resources/css/battery-ranking.css`
- `resources/views/components/portal/game-button.blade.php`
- `resources/views/components/questionnaire/splash-wire-corner.blade.php`
- `resources/views/portal/questionnaire/_experience-error-modal.blade.php`

---

## 8. Login (branding)

Layout: `resources/views/layouts/guest.blade.php`.

Serviço: `PortalAppearanceSettingService::themeForGuestLogin()`.

Configurar em **Configurações → Aparência do portal** (logo, cores, favicon) e **aba Questionário** (gradiente de fundo e logo da experiência).

---

## 9. Tela de jogar

View: `experience-play.blade.php`.

- Barra: `.qg-play__progress` + `.qg-play__progress-fill` (`width` = percentagem da pergunta actual).
- Cronómetro: `.qg-timer-wrap` + SVG (sem Font Awesome no layout game para o HUD; FA disponível para ranking).
- Confirmar: `qg-btn-iniciar` em `.qg-play__confirm-wrap`.

---

## 10. Modais (acerto e erro)

| Modal | ID / classes | Ficheiro |
|-------|----------------|----------|
| Acerto | `#qg-celebrate`, `.qg-success` | `_experience-success-modal.blade.php` |
| Erro | `#qg-miss`, `.qg-error` | `_experience-error-modal.blade.php` |

Resposta AJAX em `experience-play` (script inline): `showSuccessModal` / `showErrorModal`.

---

## 11. Tela de resultado

View: `experience-result.blade.php`.

- Não renderiza `$result['items']` (lista de perguntas).
- Usa `PortalBatteryRankingService::topTenForBattery`.
- Componente: `<x-portal.battery-ranking variant="game" :show-cta="false" />`.

---

## 12. Ranking partilhado

Componente: `resources/views/components/portal/battery-ranking.blade.php`.

Props: `variant` (`portal`|`game`), `showCta`, `headerTitle`, `headerEyebrow`.

CSS: `resources/css/battery-ranking.css`.

### Onde aparece

| Rota | Controller / serviço |
|------|----------------------|
| `/portal` | `PortalHomeController` → `PortalBatteryRankingService::topTenForUserActiveBattery` |
| `/portal/questionario/experiencia/resultado` | `PortalQuestionnaireController::experienceResult` → `topTenForBattery` |

### Regra de negócio (backend)

1. **Qual bateria:** `PortalQuestionnaireService::resolveParticipantBatteryContext` — bateria publicada + `training_group_id` do participante.
2. **Quem entra no top 10:** sessões na **mesma bateria** e **empresa**, no **mesmo grupo** do viewer, utilizador **ativo**, com **≥ 1 resposta**.
3. **Por grupo, não por área** — colegas de outras áreas no mesmo grupo aparecem no pódio; participantes de outro grupo não.
4. **Estado vazio na UI:** mensagem “Ainda não há participantes…” quando `entries` vem vazio.

Documentação completa da query: [deploy-producao-questionario-experiencia.md §16](./deploy-producao-questionario-experiencia.md#16-ranking-na-home-do-portal) e [correcao-ranking-portal-escopo-2026-05-27.md](./correcao-ranking-portal-escopo-2026-05-27.md).

### Testes

```bash
php artisan test --filter=PortalHomeRankingTest
```

Cenários cobertos: escopo legado, participante só N-N, bateria só N-N, ranking por grupo (não por área).

---

## 13. Verificação manual

1. **Login** — `/login`: logo, fundo escuro, favicon.
2. **Hub** — `/portal/questionario`: card escuro, botão fino 3D.
3. **Splash** — triângulos + botão INICIAR.
4. **Jogar** — progresso, relógio, confirmar 3D; acerto e erro com modais.
5. **Resultado** — resumo + pódio; sem lista longa de perguntas.
6. **Home portal** — ranking com palco game.

```bash
php artisan test --filter=PortalHomeRankingTest
php artisan test --filter=QuestionnaireParticipantSessionTest
php artisan test --filter=AuthenticationTest
npm run build
```

---

## 14. Manutenção

- Triângulos splash: `splash-wire-corner.blade.php`.
- Botão 3D: `game-start-button.css` (não duplicar noutros CSS).
- Pódio/ranking: `battery-ranking.css`.
- Modais: `questionnaire-game.css` (secções `.qg-celebrate`, `.qg-miss`, `.qg-error`).
- Login: `guest.blade.php` + `themeForGuestLogin`.
