{#- Career-at-a-glance timeline, driven by `criteria.career` in data/criteria.yaml. Bands tile the full width left→right. Each band's share of the width is its `weight` (defaults to its duration in years), so you can stretch or compress a phase without touching the SVG. Ticks sit at band starts; milestone dots are interpolated by year within their band, so they always line up. -#} {%- set car = criteria.career -%} {%- set X0 = 15 -%}{%- set X1 = 705 -%}{%- set W = X1 - X0 -%} {%- set gap = car.band_gap | default(4) -%} {%- set fills = car.fills or ['#dbe7f4', '#aac6e4', '#4a86c8', '#0f3f73'] -%} {%- set strokes = car.strokes or ['#aac6e4', '#8fb2d8', '', ''] -%} {#- total weight, then per-band pixel segments -#} {%- set tn = namespace(t=0) -%} {%- for b in car.bands -%}{%- set tn.t = tn.t + (b.weight | default(b.end - b.start)) -%}{%- endfor -%} {%- set total = tn.t or 1 -%} {%- set ns = namespace(cum=0, segs=[]) -%} {%- for b in car.bands -%} {%- set s0 = X0 + (ns.cum / total) * W -%} {%- set ns.cum = ns.cum + (b.weight | default(b.end - b.start)) -%} {%- set s1 = X0 + (ns.cum / total) * W -%} {%- set _ = ns.segs.append({'b': b, 's0': s0, 's1': s1}) -%} {%- endfor -%} {%- macro px(year) -%} {%- for s in ns.segs if year >= s.b.start and year <= s.b.end -%} {%- if loop.first -%}{{ (s.s0 + (year - s.b.start) / ((s.b.end - s.b.start) or 1) * (s.s1 - s.s0)) | round(1) }}{%- endif -%} {%- else -%}{{ X1 }}{%- endfor -%} {%- endmacro -%}

{{ car.caption }}

{%- for m in car.milestones %} {%- set cx = px(m.year) %} {%- set ty = 16 + loop.index0 * 18 %} {{ m.year }} — {{ m.label }} {{ m.title or m.label }} {%- endfor %} {%- for s in ns.segs %} {%- set st = strokes[loop.index0] if loop.index0 < strokes|length else '' %} {{ s.b.title }} {%- endfor %} {%- for s in ns.segs %} {{ s.b.tick | default(s.b.start) }} {%- endfor %} {{ car.end_label or 'now' }} {%- for s in ns.segs %} {%- set b = s.b %} {%- set anchor = b.anchor or 'middle' %} {%- set lx = X1 if anchor == 'end' else ((s.s0 + s.s1) / 2) | round(1) %} {#- labels alternate top/bottom row by position so neighbours never collide; override per band with an explicit label_dy in the YAML -#} {%- set ly = 96 + (b.label_dy | default(14 if loop.index0 % 2 else 0)) %} {%- set fill = b.role_fill or ('#1c1f23' if b.role_strong else '#555b63') %} {{ b.label }} {%- endfor %}