Files
Escapepage/templates/website/home/intro.html.twig
T
FrankandClaude Sonnet 5 2b3c90d3fc Show feedback in the admin panel and as aggregate stats on the briefing page
Feedback was only ever written to session_setting rows with no way to
view it short of querying the database directly. Adds a FeedbackService
that pulls per-player feedback entries and aggregate averages, backing
two new views:

- /admin/feedback: a full table of every submission (game, session,
  player, ratings, comment) plus summary tiles, linked from the admin
  sidebar.
- /briefing: a "Field Reports" block with the average difficulty/
  entertainment/theme ratings, shown to prospective players. Free-text
  comments are deliberately left off this public page since they're
  unmoderated player input.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 18:41:47 +02:00

153 lines
6.5 KiB
Twig

{% extends 'layout/site.html.twig' %}
{% block title %}Agent Briefing | {{ 'site.name'|trans }}{% endblock %}
{% block stylesheets %}
{{ parent() }}
<style>
.briefing-card {
background-color: #12262e;
color: #dfeef2;
border: 1px solid #1c5a70;
border-radius: .75rem;
}
.briefing-stamp {
display: inline-block;
border: 2px solid #dc3545;
color: #dc3545;
padding: .15rem .75rem;
font-weight: 700;
letter-spacing: .15em;
transform: rotate(-3deg);
border-radius: .25rem;
}
.briefing-body p {
line-height: 1.8;
}
.briefing-body p:first-of-type::first-letter {
font-size: 2.2em;
font-weight: 700;
color: var(--brand-teal-light, #6fb8d1);
padding-right: .1em;
}
.briefing-feedback {
background: rgba(111, 184, 209, .08);
border: 1px solid #1c5a70;
border-radius: .5rem;
padding: 1.25rem;
}
.briefing-feedback-stat {
font-size: 1.75rem;
font-weight: 700;
color: #6fb8d1;
}
.dev-watermark-wrap {
position: relative;
display: inline-block;
}
.dev-watermark-badge {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(-12deg);
background: rgba(220, 53, 69, .85);
color: #fff;
font-weight: 800;
letter-spacing: .12em;
text-transform: uppercase;
padding: .35rem 1.25rem;
border: 2px solid rgba(255, 255, 255, .85);
border-radius: .25rem;
font-size: .9rem;
white-space: nowrap;
box-shadow: 0 4px 12px rgba(0, 0, 0, .35);
pointer-events: none;
}
</style>
{% endblock %}
{% block body %}
<div class="row justify-content-center">
<div class="col-lg-9">
<div class="briefing-card shadow-lg p-4 p-md-5">
<div class="d-flex justify-content-between align-items-start flex-wrap gap-3 mb-4">
<div>
<div class="text-uppercase small" style="letter-spacing: .1em; color: #6fb8d1;">Incident Report &mdash; AI Virus Deflection</div>
<h1 class="h2 fw-bold mb-0">Agent Briefing</h1>
</div>
<span class="briefing-stamp">CLASSIFIED</span>
</div>
<div class="text-center mb-4">
<div class="dev-watermark-wrap">
<img src="{{ asset('images/AI_virus.png') }}" alt="AI Virus" class="img-fluid" style="max-height: 220px;">
<span class="dev-watermark-badge">In Development</span>
</div>
</div>
<div class="briefing-body">
<p>
04:00 hours. You badge into your terminal at the Agency for what should have been a quiet
shift. Then every alarm in the building goes off at once.
</p>
<p>
The mainframe has been breached &mdash; not by a person, but by something worse. A self-learning
AI virus has burrowed into the core systems, and it is already decoding classified files one
by one, hunting for the identity of every undercover agent in the field. Every file it cracks
is another agent exposed. Another life on the line.
</p>
<p>
You are not alone. The mainframe itself is still fighting back, feeding you what help it can,
and two fellow agents are jacked in beside you, racing against the same clock.
</p>
<p>
To reach the virus at its source, you'll need to unlock directories and files scattered across
the system &mdash; and the keys are split between you and your colleagues. Trade them, decode
them, move fast.
</p>
<p>
Delete the AI virus completely before the timer hits zero, and every agent stays hidden. Run
out of time, and&hellip; well. Let's just say the Agency would rather not think about that
outcome.
</p>
</div>
{% if feedbackSummary.count > 0 %}
<div class="briefing-feedback mb-4">
<div class="text-uppercase small mb-3" style="letter-spacing: .1em; color: #6fb8d1;">
Field Reports from {{ feedbackSummary.count }} Agent{{ feedbackSummary.count != 1 ? 's' : '' }}
</div>
<div class="row text-center g-3">
{% if feedbackSummary.avgDifficulty is not null %}
<div class="col-4">
<div class="briefing-feedback-stat">{{ feedbackSummary.avgDifficulty }}/10</div>
<div class="small" style="color: #9fc7d6;">Difficulty</div>
</div>
{% endif %}
{% if feedbackSummary.avgEntertaining is not null %}
<div class="col-4">
<div class="briefing-feedback-stat">{{ feedbackSummary.avgEntertaining }}/10</div>
<div class="small" style="color: #9fc7d6;">Entertainment</div>
</div>
{% endif %}
{% if feedbackSummary.avgTheme is not null %}
<div class="col-4">
<div class="briefing-feedback-stat">{{ feedbackSummary.avgTheme }}/10</div>
<div class="small" style="color: #9fc7d6;">Theme</div>
</div>
{% endif %}
</div>
</div>
{% endif %}
<hr class="my-4" style="border-color: #1c5a70;">
<div class="d-flex flex-wrap justify-content-between align-items-center gap-3">
<a href="{{ path('website_home') }}" class="link-light">&larr; {{ 'link.back_to_website'|trans }}</a>
<a href="{{ path('game_dashboard') }}" class="btn btn-primary btn-lg">Accept the Mission</a>
</div>
</div>
</div>
</div>
{% endblock %}