{# Shared cover renderer for list cards (feed + portfolio). Single source of truth for the three-way image branch so the favicon chip / og-image / glyph fallback never drifts between surfaces. Before this macro the portfolio template lacked the favicon branch and stretched a 32px /favicon.ico across the full cover, rendering it blurry. Args: image_url — tech_items.image_url (attacker-controllable; crawled). category — CategoryType enum or None (tints the fallback gradient). href — in-app reader URL for the card tap target. source_url — used only to label the favicon chip with its domain. transition_id — optional id. Exposed as ``data-vt`` so view-transitions.js can name *this one* cover when navigating to (or back from) its detail page, where the hero carries the same name. Never named statically: on feed→feed navigations (filter/sort) named covers would fly around on their own while the rest of each card merely crossfaded. #} {% macro cover(image_url, category, href, source_url, transition_id=None) %} {%- set cat = (category.value if category else 'none')|lower -%} {%- set vt = (' data-vt="c' ~ transition_id.hex ~ '"') if transition_id else '' -%} {%- if image_url and image_url | is_favicon -%} {# image_url is attacker-controllable (crawled): escaped only, never CSS url(). #} {{ source_url | domain }} {%- elif image_url -%} {# og:image is attacker-controllable (crawled): render via an HTML-escaped rather than inline CSS url() to avoid CSS-context injection. #} {%- else -%} {%- endif -%} {% endmacro %} {# Source stack (ARG-243) — how many outlets reported this, at a glance. Overlapping monogram discs, one per distinct domain (first four, earliest report first), then the count. A lone document shows one disc and "출처 1곳" — the same component, so single and multi-source cards never look like two different things. Monograms instead of fetched favicons: no third-party request per card. #} {% macro source_stack(domains, doc_count=1) %} {%- set n = domains | length -%}

출처 {{ n }}곳{% if doc_count > n %} 기사 {{ doc_count }}건{% endif %}

{%- endmacro %}