{% extends "base.html" %} {% block title %}{{ mission.title }} — FORGE Academy{% endblock %} {% block extra_css %} {% include "forge_academy/partials/_a11y.html" %} {% include "forge_academy/partials/_chrome_clearance.html" %} {% endblock %} {% block content %} {# aca-trn-06: the step list is the first thing in tab order, so a keyboard user had to pass every step to reach the work. #} Skip to the current step
◈ Mission
{{ mission.title }}
Tier {{ mission.tier }} · {{ mission.mission_type|capitalize }} · ~{{ mission.estimated_minutes }}m · +{{ mission.xp_reward }} XP
{# aca-trn-06: these were
  • with no role, tabindex or key handling, so the only way through a mission was a mouse. role="button" + tabindex makes each step focusable and operable, aria-current marks the one being shown, and the completed state is announced rather than left to the green tint and the glyph. #}
      {% for step in mission.steps %} {% set s_state = step_states.get(step.id, 'pending') %}
    • {{ step.title }}
    • {% endfor %}
    {% if fa_user %}
    {# aca-ux-07: the bar below fills from EARNED XP, so the number above it has to be the earned figure too. It printed the running total, which made the bar look stuck — 1815 XP over a bar that had barely moved. #}
    {{ level_ctx.earned_xp|default(0) }} earned XP · {{ level_ctx.level.label if level_ctx and level_ctx.level else 'Recruit' }}
    {% endif %}
    ← All Missions
  • {# tabindex="-1" so the skip link can actually move focus here; without it the browser scrolls but focus stays behind, and the next Tab returns to the nav. #} {# role="region", not "main": base.html already declares role="main" on #main-content, and a second main landmark is itself a violation. #}
    {# aca-trn-03: state the outcome before the first step, not after the last one. The sidebar gives tier, type, minutes and XP — all cost — and a learner started step 1 without ever being told what the mission is for. Placed above the tier-locked notice deliberately: knowing what a mission teaches is what makes "readable but earns no XP" a decision the learner can actually make. Omitted where the content states no objective (NULL), never synthesised. #} {% if mission.learning_objective %}
    Learning objective
    {{ mission.learning_objective }}
    {% endif %} {% if presenter_preview|default(false) %} {# aca-presenter-preview: the org-leadership tier (admin/pm/isso) demoing a locked mission. api_step_submit grades for real and records nothing. #}
    Presenter preview — answers are graded and shown, nothing is recorded and no XP is awarded. (Tier {{ mission.tier }} is not unlocked for this account.)
    {% elif tier_locked %} {# aca-ux-04: locked-but-readable. The content below is fully readable; the server refuses credit (api_step_submit), so state that plainly rather than letting a learner work through it and wonder where the XP went. #}
    🔒 Tier {{ mission.tier }} is not unlocked yet. Read and experiment freely — nothing here is hidden — but steps will not earn XP or count toward a certificate until it unlocks. {% if gating_state and tier_state.required_pct %}
    Requires {{ tier_state.required_pct }}% of Tier {{ tier_state.gating_tier }} — you are at {{ gating_state.pct }}% ({{ gating_state.completed }}/{{ gating_state.completable }} missions {%- if gating_state.total and gating_state.total > gating_state.completable %}, excluding {{ gating_state.total - gating_state.completable }} not yet authored {%- endif -%}).
    {% endif %}
    Go to Tier {{ tier_state.gating_tier or 1 }} missions →
    {% endif %} {% set steps = mission.steps %} {% if steps %} {% for step in steps %}
    Step {{ loop.index }} of {{ steps|length }}
    {{ step.title }}
    {% set stype = step.step_type|default('coding') %} {# aca-trn-01: a step with an authored item bank renders its questions INSTEAD of its type pane. This mirrors grade_step, where `_grade_items` already takes precedence over the declared step type — with a bank, the step is the questions. Keeping the type pane as well would leave a second, easier completion control ("✓ Understood → Continue") beside the assessment, which is a way to pass a knowledge check without answering it. `assessed_step_ids` comes from the blueprint; the questions themselves come from STEPS[idx].assessment and carry no answer key. #} {% if step.id in assessed_step_ids %} {% include "forge_academy/partials/_step_assessment.html" %} {% elif stype == 'coding' %} {% include "forge_academy/partials/_step_coding.html" %} {% elif stype == 'configure' %} {% include "forge_academy/partials/_step_configure.html" %} {% elif stype == 'verify' %} {% include "forge_academy/partials/_step_verify.html" %} {% elif stype == 'reflect' %} {% include "forge_academy/partials/_step_reflect.html" %} {% elif stype == 'watch' %} {% include "forge_academy/partials/_step_watch.html" %} {% elif stype == 'deploy' %} {% include "forge_academy/partials/_step_deploy.html" %} {% elif stype == 'design' %} {% include "forge_academy/partials/_step_design.html" %} {% else %} {% include "forge_academy/partials/_step_coding.html" %} {% endif %}
    {% endfor %} {% else %}
    Coming soon.
    This mission is on the roadmap but its content has not been authored yet. Nothing here is broken — there is simply nothing to do on it yet.
    {% endif %}
    {% endblock %}