{# Shared MARKS panel — included by booth.html (auto-gallery view) and by marks.html (the standalone page a VERBATIM index.html booth links to, since a verbatim page is served as-is and can never render this inline). One primitive, three shapes, one slot: pick — a session declared N options; the operator chooses. Renders as a radio form; answering POSTs to /answer and rewrites .marks.json. note — free text the operator volunteered, in either direction. flag — the operator pointing at one item. Rendered on the item's tile rather than here, so the judgment sits beside the artifact; the count below is the way back to them. Works with JS off — plain form POST, every shape. An answered pick shows the recorded judgment and a collapsed "change" form, because the mark is the CURRENT judgment and not a log. #} {# A mark carrying `error` is sorted out FIRST, whatever shape it claims. A pick keeps its own ⚠ broken rendering below (richer — it has a declaration to show); a broken note would otherwise render as an empty
 with a withdraw
   button, indistinguishable from a note the operator wrote and then cleared,
   and a broken flag would link to a target that is not there. Unreadable state
   is visible state — the rule `_hydrate` states for picks, applied to all
   three. #}
{% set broken = marks | selectattr('error') | rejectattr('shape', 'equalto', 'pick') | list %}
{% set picks = marks | selectattr('shape', 'equalto', 'pick') | list %}
{% set notes = marks | selectattr('shape', 'equalto', 'note') | rejectattr('error') | list %}
{% set flags = marks | selectattr('shape', 'equalto', 'flag') | rejectattr('error') | list %}
{# `picks_only` + `back_view`: the review rail (view.html) includes this panel with `marks` narrowed to the open picks it should offer, and wants only the pick forms, each landing back on the review (`back=view`, R2 C3). ONE renderer of a pick form, whichever page it sits on. #} {% if not picks_only %} {% for a in broken %}
⚠ broken {{ a.id }}
{% if marks_page %}{% endif %}

This mark could not be read: {{ a.error }}

{% endfor %} {% endif %} {% for a in picks %}
{% if a.error %}⚠ broken{% elif a.answer and a.answer.complete %}✓ answered{% elif a.answer %}◐ partial{% else %}? open{% endif %} {{ a.id }}{% if a.multi %} · {{ a.questions|length }} questions{% endif %} {% if a.target %}on {{ a.target }}{% endif %} {% if a.answer and not a.answer.complete %}{{ (a.questions|length) - (a.answer.unanswered|length) }}/{{ a.questions|length }}{% endif %} {% if a.answer %}{{ a.answer.answered_at }}{% if a.answer.answered_by %} · {{ a.answer.answered_by }}{% endif %}{% endif %}
{% if a.error %}

This question could not be read: {{ a.error }}

{% else %} {% if a.title and not a.multi %}

{{ a.title }}

{% endif %}

{{ a.prompt }}

{% if a.answer %}
{% if a.multi %} {% for q in a.questions %}{% set qa = a.answer.answers.get(q.key) %}
{{ q.prompt }}
{{ qa.label if (qa and qa.choice is not none) else 'left blank' }}
{% if qa and qa.notes %}
{{ qa.notes }}
{% endif %}
{% endfor %} {% else %}
{{ a.answer.label }}
{% endif %} {% if a.answer.notes %}
{{ a.answer.notes }}
{% endif %}
{% endif %}
{% if a.answer %}change answer{% else %}answer{% endif %}
{# The field is still `ask`: inline fragments in reports the operator has already published POST that name, and breaking every landed verbatim report to tidy a form field is not a trade worth making. #} {# On the standalone page, come back HERE — the booth's own page is a verbatim report that cannot show the recorded judgment. #} {% if marks_page %}{% endif %} {% if back_view %}{% endif %} {% for q in a.questions %} {% set field = 'choice.' ~ q.key if a.multi else 'choice' %} {% set qa = a.answer.answers.get(q.key) if (a.answer and a.multi) else a.answer %}
{% if a.multi %}{{ loop.index }}. {{ q.prompt }}{% endif %}
{% for o in q.options %} {% endfor %}
{% if q.notes %} {% endif %}
{% endfor %} {% if a.notes_enabled %} {% endif %}
{% endif %}
{% endfor %} {% if not picks_only %} {# FLAGS come right after the picks. On the lightbox (`tray` defined) they render as the TRAY: the flagged items in SET order — by tile number, the declared R2 change from the click order below — each the original shown small, blurred if the item is. The standalone marks page has no item records, so it keeps the list, in `(created, id)` order. #} {% if tray is defined %}{% if tray %} {# In the lightbox the tray and the notes FOLD on a narrow screen (R2 C5): a closed
, which base.html shows open-and-summary-less above 1000px with no script. Below it, the question sits above the set and the tray and notes are one tap away instead of burying it. #}
✔ flagged · {{ tray|length }}
{% endif %} {% if orphan_flags %}
✔ flagged {{ orphan_flags|length }} on files no longer in this booth
    {% for m in orphan_flags %}
  • {{ m.target }}
  • {% endfor %}
{% endif %} {% elif flags %}
✔ flagged {{ flags|length }} item{{ '' if flags|length == 1 else 's' }}
{% endif %} {% set fold_notes = tray is defined and notes %} {% if fold_notes %}
notes · {{ notes|length }}{% endif %} {% for a in notes %}
note {% if a.target %}on {{ a.target }} {% else %}on this booth{% endif %} {{ a.created }}{% if a.by %} · {{ a.by }}{% endif %}
{% if marks_page %}{% endif %}
{{ a.text }}
{% endfor %} {% if fold_notes %}
{% endif %} {# The operator volunteering a remark, which before marks had no mechanism at all — this is the direction that was running through chat. #}
{% if marks_page %}{% endif %}
{% endif %}