{% extends "@FerienpassAdmin/layout/base.html.twig" %}
{% trans_default_domain 'admin' %}
{% set title = edition.name ~ ' · ' ~ ('stats.title'|trans) %}
{% import _self as ui %}

{#
   Saison-Statistik — /admin/saisons/<slug>/statistik

   One self-contained template. All charts are plain SVG/HTML+Tailwind so the
   page renders zero JS for chart bodies; each chart card carries a
   data-chart="…" hook so a future Plotly upgrade can swap the body of a card
   without touching layout. Data comes pre-shaped from EditionStatsBuilder —
   templates do NO aggregation, only formatting.
#}

{# ─────── Color tokens ─────── #}
{# Full literal strings so the Tailwind scanner picks them up. Indexed by tone. #}
{% set tones = {
    gray:    {bar: '#9ca3af', pale: '#f3f4f6', text: 'text-gray-700',    badgeRing: 'bg-gray-50 text-gray-700 ring-gray-200'},
    indigo:  {bar: '#4f46e5', pale: '#e0e7ff', text: 'text-indigo-700',  badgeRing: 'bg-indigo-50 text-indigo-700 ring-indigo-200'},
    emerald: {bar: '#10b981', pale: '#d1fae5', text: 'text-emerald-700', badgeRing: 'bg-emerald-50 text-emerald-700 ring-emerald-200'},
    amber:   {bar: '#f59e0b', pale: '#fef3c7', text: 'text-amber-700',   badgeRing: 'bg-amber-50 text-amber-700 ring-amber-200'},
    rose:    {bar: '#f43f5e', pale: '#ffe4e6', text: 'text-rose-700',    badgeRing: 'bg-rose-50 text-rose-700 ring-rose-200'},
    cyan:    {bar: '#06b6d4', pale: '#cffafe', text: 'text-cyan-700',    badgeRing: 'bg-cyan-50 text-cyan-700 ring-cyan-200'},
    sky:     {bar: '#0ea5e9', pale: '#e0f2fe', text: 'text-sky-700',     badgeRing: 'bg-sky-50 text-sky-700 ring-sky-200'},
} %}

{#
   ─────── Macros ───────
   Each macro is one chart "primitive". Inputs are the DTO-array shapes from
   EditionStats; no further reshaping happens here.
#}

{% macro nfmt(n) %}{{ n|number_format(0, ',', '.') }}{% endmacro %}

{# ── KPI tile ── #}
{% macro kpi(label, value, suffix, delta, deltaSuffix, bench) %}
    {% import _self as self %}
    <div class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg p-4">
        <div class="text-xs font-medium text-gray-500 dark:text-gray-400">{{ label|trans }}</div>
        <div class="mt-1 flex items-baseline gap-2">
            <span class="text-3xl font-extrabold text-gray-900 dark:text-gray-50 tabular-nums tracking-tight">
                {% if suffix == '%' %}{{ value|number_format(1, ',', '.') }}{% else %}{{ self.nfmt(value) }}{% endif %}
            </span>
            {% if suffix %}<span class="text-base font-semibold text-gray-400 dark:text-gray-500">{{ suffix }}</span>{% endif %}
        </div>
        {% if bench %}
            <div class="mt-2 flex items-center gap-2">
                {% if delta is null or delta == 0 %}
                    <span class="text-[11px] font-semibold text-gray-400 dark:text-gray-500">±0{{ deltaSuffix }}</span>
                {% else %}
                    {% set up = delta > 0 %}
                    <span class="inline-flex items-center gap-0.5 text-[11px] font-semibold {{ up ? 'text-emerald-700 dark:text-emerald-400' : 'text-rose-700 dark:text-rose-400' }}">
                        <svg viewBox="0 0 256 256" fill="currentColor" class="size-3 {{ up ? '' : 'rotate-180' }}"><path d="M205.66 117.66a8 8 0 0 1-11.32 0L136 59.31V216a8 8 0 0 1-16 0V59.31l-58.34 58.35a8 8 0 0 1-11.32-11.32l72-72a8 8 0 0 1 11.32 0l72 72a8 8 0 0 1 0 11.32"/></svg>
                        {{ up ? '+' : '' }}{% if deltaSuffix == '%' %}{{ delta|number_format(1, ',', '.') }}{% else %}{{ delta }}{% endif %}{{ deltaSuffix }}
                    </span>
                {% endif %}
                <span class="text-[11px] text-gray-400 dark:text-gray-500 truncate" title="{{ ('stats.compare.vs'|trans({'bench': bench})) }}">{{ ('stats.compare.vs'|trans({'bench': bench})) }}</span>
            </div>
        {% else %}
            <div class="mt-2 h-[18px]"></div>
        {% endif %}
    </div>
{% endmacro %}

{# ── Daily signups SVG line ── #}
{% macro dailySignups(data) %}
    {% if data|length == 0 %}{% import _self as self %}{{ self.empty() }}{% else %}
        {% set w = 720 %}{% set h = 200 %}{% set padL = 36 %}{% set padR = 12 %}{% set padT = 16 %}{% set padB = 28 %}
        {% set innerW = w - padL - padR %}{% set innerH = h - padT - padB %}
        {% set max = (data|reduce((c, d) => d.n > c ? d.n : c, 0)) %}
        {% if max < 1 %}{% set max = 1 %}{% endif %}
        {% set len = data|length %}
        <div class="overflow-hidden">
            <svg viewBox="0 0 {{ w }} {{ h }}" class="w-full h-auto" preserveAspectRatio="none">
                <defs>
                    <linearGradient id="g-signups" x1="0" x2="0" y1="0" y2="1">
                        <stop offset="0%" stop-color="#4f46e5" stop-opacity="0.25"/>
                        <stop offset="100%" stop-color="#4f46e5" stop-opacity="0.02"/>
                    </linearGradient>
                </defs>
                {# gridlines + Y ticks #}
                {% for f in [0, 0.25, 0.5, 0.75, 1] %}
                    {% set yPx = padT + innerH - (f * innerH) %}
                    <line x1="{{ padL }}" x2="{{ w - padR }}" y1="{{ yPx }}" y2="{{ yPx }}" stroke="#f3f4f6" stroke-width="1"/>
                    <text x="{{ padL - 6 }}" y="{{ yPx + 3 }}" font-size="10" fill="#9ca3af" text-anchor="end">{{ (max * f)|round(0) }}</text>
                {% endfor %}
                {# Build polyline points via {% set %} string-capture (Twig has no
                   mutable cross-iteration variable; this is the idiomatic workaround). #}
                {% set linePts %}{% for i, d in data %}{% set xPx = padL + (i / (len - 1 < 1 ? 1 : len - 1)) * innerW %}{% set yPx = padT + innerH - (d.n / max) * innerH %}{% if not loop.first %} L {% endif %}{{ xPx }},{{ yPx }}{% endfor %}{% endset %}
                {% set firstPx = padL %}
                <path d="M {{ linePts }} L {{ padL + innerW }},{{ padT + innerH }} L {{ firstPx }},{{ padT + innerH }} Z" fill="url(#g-signups)"/>
                <path d="M {{ linePts }}" fill="none" stroke="#4f46e5" stroke-width="2" stroke-linejoin="round" stroke-linecap="round"/>
                {# sparse points + x ticks #}
                {% for i, d in data %}
                    {% if i % 7 == 0 or i == len - 1 %}
                        {% set xPx = padL + (i / (len - 1 < 1 ? 1 : len - 1)) * innerW %}
                        {% set yPx = padT + innerH - (d.n / max) * innerH %}
                        <circle cx="{{ xPx }}" cy="{{ yPx }}" r="2.5" fill="#4f46e5"/>
                        <text x="{{ xPx }}" y="{{ h - 8 }}" font-size="10" fill="#9ca3af" text-anchor="middle">
                            {{ d.date|date('d.m.') }}
                        </text>
                    {% endif %}
                {% endfor %}
            </svg>
        </div>
    {% endif %}
{% endmacro %}

{# ── Empty state ── #}
{% macro empty(message = null) %}
    <div class="py-8 text-center text-sm text-gray-400 dark:text-gray-500 italic">
        {{ (message ?: 'stats.empty')|trans }}
    </div>
{% endmacro %}

{# ── Vertical bar histogram (used by Age, Utilization, ConfirmedPerKid) ── #}
{% macro vbars(rows, tones, labelKey, defaultTone = 'indigo') %}
    {% import _self as self %}
    {% set max = (rows|reduce((c, r) => r.n > c ? r.n : c, 0)) %}
    {% if max < 1 %}{% set max = 1 %}{% endif %}
    {% set barArea = 132 %}
<div class="flex items-end justify-between gap-2">
        {% for r in rows %}
            {% set h = ((r.n / max) * barArea)|round %}{% if h < 2 %}{% set h = 2 %}{% endif %}
            {% set tone = r.tone is defined and r.tone ? r.tone : defaultTone %}
            <div class="flex-1 flex flex-col items-center gap-1.5 min-w-0">
                <div class="text-[11px] tabular-nums font-semibold" style="color:{{ tones[tone].bar }};">{{ r.n }}</div>
                <div class="w-full rounded-t-sm" style="height:{{ h }}px;background:{{ tones[tone].bar }};" title="{{ attribute(r, labelKey) }}: {{ r.n }}"></div>
                <div class="text-[10px] text-gray-500 dark:text-gray-400 whitespace-nowrap">{{ attribute(r, labelKey) }}</div>
            </div>
        {% endfor %}
    </div>
{% endmacro %}

{# ── Status funnel ── #}
{% macro funnel(steps, tones) %}
    {% import _self as self %}
    {% set max = (steps|reduce((c, s) => s.count > c ? s.count : c, 0)) %}
    {% if max < 1 %}{% set max = 1 %}{% endif %}
    {% set anchor = steps|first %}
    <div class="flex flex-col gap-y-2.5">
        {% for s in steps %}
            {% set pct = ((s.count / max) * 100) %}
            {% set pctOfTotal = anchor.count > 0 ? ((s.count / anchor.count) * 100)|round : 0 %}
            {% set next = steps[loop.index] ?? null %}
            {% set dropoff = next and s.count > 0 ? ((1 - next.count / s.count) * 100)|round : null %}
            <div>
                <div class="flex items-baseline justify-between text-xs mb-1">
                    <span class="font-semibold text-gray-700 dark:text-gray-300">{{ s.label|trans }}</span>
                    <span class="tabular-nums text-gray-900 dark:text-gray-50 font-semibold">{{ self.nfmt(s.count) }}</span>
                </div>
                <div class="relative h-7 rounded-md bg-gray-50 dark:bg-gray-800 overflow-hidden">
                    <div class="absolute inset-y-0 left-0 rounded-md" style="width:{{ pct }}%;background:{{ tones[s.tone].bar }};"></div>
                    <div class="relative h-full flex items-center pl-3">
                        <span class="text-[11px] font-medium text-white drop-shadow-sm">{{ pctOfTotal }}% {{ 'funnel.of.attendances'|trans }}</span>
                    </div>
                </div>
                {% if dropoff is not null and dropoff > 0 %}
                    <div class="text-[10px] text-gray-400 dark:text-gray-500 mt-1 text-right">↓ {{ dropoff }}% {{ 'funnel.dropoff'|trans }}</div>
                {% endif %}
            </div>
        {% endfor %}
    </div>
{% endmacro %}

{# ── BarList: Anmeldungen vs. Plätze (categories, top/flop offers) ── #}
{% macro barList(rows, tones) %}
    {% import _self as self %}
    {% set max = (rows|reduce((c, r) => (r.signups > r.slots ? r.signups : r.slots) > c ? (r.signups > r.slots ? r.signups : r.slots) : c, 0)) %}
    {% if max < 1 %}{% set max = 1 %}{% endif %}
    <div class="flex flex-col gap-y-3">
        {% for r in rows %}
            {% set util = r.slots > 0 ? ((r.signups / r.slots) * 100)|round : 0 %}
            {% set over = r.signups > r.slots %}
            {% set tone = over ? 'rose' : (util >= 90 ? 'emerald' : (util >= 60 ? 'amber' : 'gray')) %}
            {% set slotsPct = (r.slots / max) * 100 %}
            {% set fitPct = ((r.signups > r.slots ? r.slots : r.signups) / max) * 100 %}
            {% set overflowPct = over ? ((r.signups - r.slots) / max) * 100 : 0 %}
            <div>
                <div class="flex items-baseline justify-between text-xs mb-1 gap-3">
                    <div class="min-w-0">
                        <div class="font-medium text-gray-700 dark:text-gray-300 truncate">{{ r.label }}</div>
                        {% if r.sub is defined and r.sub %}<div class="text-[11px] text-gray-400 dark:text-gray-500 truncate">{{ r.sub }}</div>{% endif %}
                    </div>
                    <div class="shrink-0 text-gray-500 dark:text-gray-400 whitespace-nowrap">
                        <span class="tabular-nums text-gray-900 dark:text-gray-50 font-semibold">{{ self.nfmt(r.signups) }}</span>
                        <span class="text-gray-400 dark:text-gray-500"> {{ 'bar.signupsShort'|trans }} / {{ self.nfmt(r.slots) }} {{ 'bar.slots'|trans }} · </span>
                        <span class="font-semibold tabular-nums {{ tones[tone].text }}">{{ util }}%</span>
                        {% if over %}
                            <span class="ml-1.5 inline-flex items-center rounded-full bg-rose-50 text-rose-700 ring-1 ring-inset ring-rose-200 dark:bg-rose-950 dark:text-rose-300 dark:ring-rose-900 px-1.5 py-0.5 text-[10px] font-semibold">
                                +{{ self.nfmt(r.signups - r.slots) }} {{ 'bar.unmet'|trans }}
                            </span>
                        {% endif %}
                    </div>
                </div>
                <div class="relative h-2 rounded-full bg-gray-100 dark:bg-gray-800 overflow-hidden">
                    <div class="absolute inset-y-0 left-0 bg-gray-200 dark:bg-gray-700" style="width:{{ slotsPct }}%;"></div>
                    <div class="absolute inset-y-0 left-0" style="width:{{ fitPct }}%;background:{{ over ? tones.emerald.bar : tones[tone].bar }};"></div>
                    {% if over %}
                        <div class="absolute inset-y-0" style="left:{{ slotsPct }}%;width:{{ overflowPct }}%;background:{{ tones.rose.bar }};"></div>
                        <div class="absolute inset-y-0 w-px bg-white/90" style="left:{{ slotsPct }}%;"></div>
                    {% endif %}
                </div>
            </div>
        {% endfor %}
    </div>
{% endmacro %}

{# ── Status share: single stacked horizontal bar + legend ── #}
{% macro statusShare(segments, total, tones) %}
    {% import _self as self %}
    <div class="grid grid-cols-1 lg:grid-cols-[auto_1fr] gap-x-8 gap-y-5 items-center">
        <div class="min-w-0">
            <div class="text-4xl font-extrabold text-gray-900 dark:text-gray-50 tabular-nums tracking-tight">{{ self.nfmt(total) }}</div>
            <div class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'share.total'|trans }}</div>
        </div>
        <div class="min-w-0">
            <div class="flex h-8 rounded-md overflow-hidden ring-1 ring-inset ring-black/5 dark:ring-white/10">
                {% for s in segments %}
                    {% set pct = total > 0 ? (s.n / total) * 100 : 0 %}
                    <div class="relative flex items-center justify-start px-2" style="width:{{ pct }}%;background:{{ tones[s.tone].bar }};" title="{{ s.label|trans }}: {{ self.nfmt(s.n) }} ({{ pct|number_format(1, ',', '.') }}%)">
                        {% if pct > 5 %}
                            <span class="text-[11px] font-bold text-white drop-shadow-sm tabular-nums">{{ pct|number_format(1, ',', '.') }}%</span>
                        {% endif %}
                    </div>
                {% endfor %}
            </div>
            <div class="mt-3 grid grid-cols-1 gap-x-4 gap-y-2 sm:grid-cols-{{ segments|length >= 4 ? 2 : 3 }} lg:grid-cols-{{ segments|length }}">
                {% for s in segments %}
                    {% set pct = total > 0 ? (s.n / total) * 100 : 0 %}
                    <div class="flex items-start gap-2.5">
                        <span class="size-3 rounded-sm mt-1 shrink-0" style="background:{{ tones[s.tone].bar }};"></span>
                        <div class="min-w-0">
                            <div class="text-[11px] text-gray-500 dark:text-gray-400">{{ s.label|trans }}</div>
                            <div class="flex items-baseline gap-1.5">
                                <span class="text-base font-bold text-gray-900 dark:text-gray-50 tabular-nums">{{ self.nfmt(s.n) }}</span>
                                <span class="text-[11px] text-gray-400 dark:text-gray-500 font-medium tabular-nums">{{ pct|number_format(1, ',', '.') }}%</span>
                            </div>
                            {% if s.desc is defined and s.desc %}
                                <div class="text-[11px] text-gray-400 dark:text-gray-500 mt-0.5">{{ s.desc|trans }}</div>
                            {% endif %}
                        </div>
                    </div>
                {% endfor %}
            </div>
        </div>
    </div>
{% endmacro %}

{# ── Dense histogram (per-day / per-€) ── #}
{% macro denseHistogram(buckets, tones) %}
    {% set max = (buckets|reduce((c, b) => b.n > c ? b.n : c, 0)) %}
    {% if max < 1 %}{% set max = 1 %}{% endif %}
    {% set barArea = 160 %}
    <div>
<div class="flex items-end gap-[2px]">
            {% for b in buckets %}
                {% set h = ((b.n / max) * barArea)|round %}{% if h < 1 %}{% set h = 1 %}{% endif %}
                {% set isPeak = b.n == max and b.n > 0 %}
                <div class="flex-1 flex flex-col items-center min-w-0" title="{{ b.label|trans }}: {{ b.n }}">
                    <div class="text-[9px] tabular-nums leading-none mb-0.5 {{ isPeak or b.highlight ? 'font-semibold' : '' }}" style="color:{{ tones[b.tone].bar }};">
                        {{ b.n > 0 ? b.n : '' }}
                    </div>
                    <div class="w-full rounded-t-sm" style="height:{{ h }}px;background:{{ tones[b.tone].bar }};"></div>
                </div>
            {% endfor %}
        </div>
        <div class="flex items-start gap-[2px] mt-1.5">
            {% for b in buckets %}
                <div class="flex-1 text-center text-[9px] text-gray-500 dark:text-gray-400 tabular-nums whitespace-nowrap leading-tight">
                    {{ b.axisLabel|trans }}
                </div>
            {% endfor %}
        </div>
    </div>
{% endmacro %}

{# ── Hour-of-day histogram (24 thin bars) ── #}
{% macro hourHistogram(data, tones) %}
    {% set max = (data|reduce((c, d) => d.n > c ? d.n : c, 0)) %}
    {% if max < 1 %}{% set max = 1 %}{% endif %}
    {% set barArea = 150 %}
    <div>
        <div class="flex items-end gap-[2px]">
            {% for d in data %}
                {% set h = ((d.n / max) * barArea)|round %}{% if h < 2 %}{% set h = 2 %}{% endif %}
                {% set peak = d.n == max and d.n > 0 %}
<div class="flex-1 flex flex-col items-center min-w-0" title="{{ '%02d'|format(d.h) }}:00 — {{ d.n }} {{ 'unit.signups'|trans }}">
                    {% set barColor = peak ? tones.rose.bar : tones.indigo.bar %}
                    <div class="text-[9px] tabular-nums leading-none mb-0.5 {{ peak ? 'font-bold' : '' }}" style="color:{{ barColor }};">
                        {{ d.n > 0 ? d.n : '' }}
                    </div>
                    <div class="w-full rounded-t-sm" style="height:{{ h }}px;background:{{ barColor }};"></div>
                </div>
            {% endfor %}
        </div>
        <div class="flex items-start gap-[2px] mt-1.5">
            {% for d in data %}
                <div class="flex-1 text-center text-[9px] text-gray-500 dark:text-gray-400 tabular-nums">{{ d.h % 3 == 0 ? '%02d:00'|format(d.h) : '' }}</div>
            {% endfor %}
        </div>
    </div>
{% endmacro %}

{# ── Paired histogram: applied per kid vs. confirmed per kid ── #}
{% macro pairedKidHistogram(applied, confirmed, tones) %}
    {% set buckets = [0, 1, 2, 3, 4, 5, 6] %}
    {% set maxA = (applied|reduce((c, a) => a.n > c ? a.n : c, 0)) %}
    {% set maxC = (confirmed|reduce((c, x) => x.n > c ? x.n : c, 0)) %}
    {% set max = maxA > maxC ? maxA : maxC %}{% if max < 1 %}{% set max = 1 %}{% endif %}
    {% set barArea = 140 %}
    <div>
        <div class="flex items-end justify-between gap-3">
            {% for b in buckets %}
                {% set aRow = applied|filter(x => x.count == b)|first %}
                {% set cRow = confirmed|filter(x => x.spots == b)|first %}
                {% set aN = aRow ? aRow.n : 0 %}
                {% set cN = cRow ? cRow.n : 0 %}
                {% set aH = ((aN / max) * barArea)|round %}
                {% set cH = ((cN / max) * barArea)|round %}
                <div class="flex-1 flex flex-col items-center min-w-0">
                    <div class="flex items-end gap-1 w-full justify-center" style="height:{{ barArea + 16 }}px;">
                        <div class="flex-1 max-w-[18px] flex flex-col justify-end items-center">
                            {% if aN > 0 %}<div class="text-[9px] tabular-nums text-gray-500 dark:text-gray-400 mb-0.5">{{ aN }}</div>{% endif %}
                            <div class="w-full rounded-t-sm" style="height:{{ aH }}px;background:{{ tones.indigo.bar }};opacity:.85;"></div>
                        </div>
                        <div class="flex-1 max-w-[18px] flex flex-col justify-end items-center">
                            {% if cN > 0 %}<div class="text-[9px] tabular-nums text-gray-500 dark:text-gray-400 mb-0.5">{{ cN }}</div>{% endif %}
                            <div class="w-full rounded-t-sm" style="height:{{ cH }}px;background:{{ tones.emerald.bar }};"></div>
                        </div>
                    </div>
                    <div class="text-[10px] text-gray-500 dark:text-gray-400 mt-1">{{ b }}{{ b == 6 ? '+' : '' }}</div>
                </div>
            {% endfor %}
        </div>
        <div class="mt-3 flex items-center justify-center gap-4 text-[11px] text-gray-600 dark:text-gray-300">
            <span class="inline-flex items-center gap-1.5"><span class="size-2.5 rounded-sm" style="background:{{ tones.indigo.bar }};opacity:.85;"></span>{{ 'pair.applied'|trans }}</span>
            <span class="inline-flex items-center gap-1.5"><span class="size-2.5 rounded-sm" style="background:{{ tones.emerald.bar }};"></span>{{ 'pair.confirmed'|trans }}</span>
        </div>
    </div>
{% endmacro %}

{# ── Simple bar list (one value per row, eg PLZ) ── #}
{% macro simpleBarList(rows, tones) %}
    {% import _self as self %}
    {% set max = (rows|reduce((c, r) => r.n > c ? r.n : c, 0)) %}{% if max < 1 %}{% set max = 1 %}{% endif %}
    {% set total = (rows|reduce((c, r) => c + r.n, 0)) %}{% if total < 1 %}{% set total = 1 %}{% endif %}
    <div class="flex flex-col gap-y-2.5">
        {% for r in rows %}
            {% set pct = ((r.n / total) * 100)|round %}
            <div>
                <div class="flex items-baseline justify-between text-xs mb-1 gap-3">
                    <div class="min-w-0 truncate">
                        {% if r.plz is defined and r.plz %}<span class="text-[11px] text-gray-400 dark:text-gray-500 mr-1.5 tabular-nums">{{ r.plz }}</span>{% endif %}
                        {% if r.label %}<span class="font-medium text-gray-700 dark:text-gray-300">{{ r.label }}</span>{% endif %}
                    </div>
                    <div class="shrink-0 text-gray-500 dark:text-gray-400 whitespace-nowrap">
                        <span class="tabular-nums text-gray-900 dark:text-gray-50 font-semibold">{{ self.nfmt(r.n) }}</span>
                        <span class="text-[11px] text-gray-400 dark:text-gray-500 ml-1.5">{{ pct }}%</span>
                    </div>
                </div>
                <div class="relative h-2 rounded-full bg-gray-100 dark:bg-gray-800 overflow-hidden">
                    <div class="absolute inset-y-0 left-0 rounded-full" style="width:{{ (r.n / max) * 100 }}%;background:{{ tones.indigo.bar }};"></div>
                </div>
            </div>
        {% endfor %}
    </div>
{% endmacro %}

{# ── Top vendors table ── #}
{% macro topVendors(rows) %}
    {% import _self as self %}
    <div class="overflow-hidden">
        <table class="w-full text-sm">
            <thead>
                <tr class="text-left text-[11px] font-semibold text-gray-400 dark:text-gray-500">
                    <th class="py-1.5 pr-2 font-semibold">{{ 'vendor.col.host'|trans }}</th>
                    <th class="py-1.5 px-2 text-right font-semibold">{{ 'vendor.col.offers'|trans }}</th>
                    <th class="py-1.5 px-2 text-right font-semibold">{{ 'vendor.col.signups'|trans }}</th>
                    <th class="py-1.5 pl-2 text-right font-semibold">{{ 'vendor.col.utilization'|trans }}</th>
                </tr>
            </thead>
            <tbody class="divide-y divide-gray-100 dark:divide-white/5">
                {% for v in rows %}
                    <tr class="hover:bg-gray-50/60 dark:hover:bg-white/5">
                        <td class="py-2 pr-2 text-gray-900 dark:text-gray-100 font-medium truncate max-w-xs">{{ v.name }}</td>
                        <td class="py-2 px-2 text-right tabular-nums text-gray-700 dark:text-gray-300">{{ v.offers }}</td>
                        <td class="py-2 px-2 text-right tabular-nums text-gray-900 dark:text-gray-50 font-semibold">{{ self.nfmt(v.signups) }}</td>
                        <td class="py-2 pl-2 text-right">
                            <span class="inline-flex items-center gap-1.5">
                                <span class="w-12 h-1 rounded-full bg-gray-100 dark:bg-gray-800 overflow-hidden inline-block">
                                    <span class="block h-full {{ v.util >= 90 ? 'bg-emerald-500' : (v.util >= 60 ? 'bg-amber-500' : 'bg-rose-500') }}" style="width:{{ v.util > 100 ? 100 : v.util }}%;"></span>
                                </span>
                                <span class="tabular-nums text-gray-900 dark:text-gray-50 text-xs">{{ v.util }}%</span>
                            </span>
                        </td>
                    </tr>
                {% endfor %}
            </tbody>
        </table>
    </div>
{% endmacro %}

{# ── Section heading (typographic separator between stats sections) ── #}
{% macro section(title) %}
    <div class="mt-2 first:mt-0 flex items-center gap-3 pt-3">
        <div class="text-[11px] font-bold uppercase tracking-wider text-gray-500 dark:text-gray-400">{{ title|trans }}</div>
        <div class="flex-1 h-px bg-gray-200 dark:bg-white/10"></div>
    </div>
{% endmacro %}

{# ── ComparePicker (pill button popover) ── #}
{% macro comparePicker(current, candidates, baseAlias) %}
    {% set currentLabel = current ? current.name : null %}
    <div class="relative" x-data="{ open: false }" @keydown.escape="open = false" @click.outside="open = false">
        <button type="button" @click="open = !open"
                class="inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-semibold shadow-sm ring-1 ring-inset transition
                       {{ current
                            ? 'bg-primary-50 text-primary-700 ring-primary-200 hover:bg-primary-100 dark:bg-primary-950 dark:text-primary-300 dark:ring-primary-900'
                            : 'bg-white text-gray-700 ring-gray-300 hover:bg-gray-50 dark:bg-gray-900 dark:text-gray-200 dark:ring-white/10 dark:hover:bg-gray-800' }}"
                :aria-expanded="open">
            <span class="size-4"><svg viewBox="0 0 256 256" fill="currentColor"><path d="M232 128a8 8 0 0 1-8 8H115.31l34.35 34.34a8 8 0 0 1-11.32 11.32l-48-48a8 8 0 0 1 0-11.32l48-48a8 8 0 0 1 11.32 11.32L115.31 120H224a8 8 0 0 1 8 8M192 32H32a8 8 0 0 0-8 8v176a8 8 0 0 0 16 0V48h152a8 8 0 0 0 0-16"/></svg></span>
            <span>{{ current ? ('stats.compare.active'|trans({'name': currentLabel})) : 'stats.compare.choose'|trans }}</span>
            <span class="size-3.5 transition-transform" :class="open ? 'rotate-180' : ''"><svg viewBox="0 0 256 256" fill="currentColor"><path d="M213.66 101.66l-80 80a8 8 0 0 1-11.32 0l-80-80a8 8 0 0 1 11.32-11.32L128 164.69l74.34-74.35a8 8 0 0 1 11.32 11.32"/></svg></span>
        </button>

        <div x-show="open" x-cloak x-transition.opacity
             class="absolute right-0 z-30 mt-2 w-[300px] rounded-lg bg-white dark:bg-gray-900 shadow-xl ring-1 ring-black/5 dark:ring-white/10 overflow-hidden">
            <a href="{{ path('admin_editions_stats', {alias: baseAlias}) }}"
               class="w-full flex items-center gap-3 px-3 py-2.5 text-left border-b border-gray-100 dark:border-white/5 {{ not current ? 'bg-primary-50/60 dark:bg-primary-950/60' : 'hover:bg-gray-50 dark:hover:bg-white/5' }}">
                <span class="size-4 rounded-full flex items-center justify-center ring-1 {{ not current ? 'ring-primary-600 bg-primary-600' : 'ring-gray-300 dark:ring-white/20' }}">
                    {% if not current %}<span class="size-1.5 rounded-full bg-white"></span>{% endif %}
                </span>
                <span class="flex-1 min-w-0">
                    <span class="block text-sm font-semibold text-gray-900 dark:text-gray-50">{{ 'stats.compare.none'|trans }}</span>
                    <span class="block text-xs text-gray-500 dark:text-gray-400">{{ 'stats.compare.none.desc'|trans }}</span>
                </span>
            </a>
            <div class="px-3 py-1.5 text-[11px] font-semibold uppercase tracking-wider text-gray-400 dark:text-gray-500 bg-gray-50/60 dark:bg-gray-950/60 border-b border-gray-100 dark:border-white/5">{{ 'stats.compare.candidates'|trans }}</div>
            <ul class="max-h-[280px] overflow-y-auto">
                {% for cand in candidates %}
                    {% set sel = current and current.id == cand.id %}
                    <li>
                        <a href="{{ path('admin_editions_stats', {alias: baseAlias, compare: cand.alias}) }}"
                           class="w-full flex items-center gap-3 px-3 py-2 text-left {{ sel ? 'bg-primary-50/60 dark:bg-primary-950/60' : 'hover:bg-gray-50 dark:hover:bg-white/5' }}">
                            <span class="size-4 rounded-full flex items-center justify-center ring-1 {{ sel ? 'ring-primary-600 bg-primary-600' : 'ring-gray-300 dark:ring-white/20' }}">
                                {% if sel %}<span class="size-1.5 rounded-full bg-white"></span>{% endif %}
                            </span>
                            <span class="flex-1 text-sm {{ sel ? 'font-semibold text-gray-900 dark:text-gray-50' : 'text-gray-800 dark:text-gray-200' }}">{{ cand.name }}</span>
                        </a>
                    </li>
                {% else %}
                    <li class="px-3 py-3 text-sm text-gray-500 dark:text-gray-400 italic">{{ 'stats.compare.empty'|trans }}</li>
                {% endfor %}
            </ul>
        </div>
    </div>
{% endmacro %}


{# ─────── PAGE ─────── #}

{% block main %}

    <twig:Admin:Edition:Header edition="{{ edition }}"/>

    {# Page-level header with comparison picker #}
    <div class="flex flex-col gap-y-3 sm:flex-row sm:items-end sm:justify-between py-5 border-b border-gray-200 dark:border-white/10">
        <div class="min-w-0">
            <h2 class="text-xl sm:text-2xl font-extrabold tracking-tight text-gray-900 dark:text-gray-50">{{ 'stats.title'|trans }}</h2>
            {% if stats.eventWindow %}
                <p class="mt-1.5 text-sm text-gray-500 dark:text-gray-400">{{ 'stats.eventWindow'|trans({'start': stats.eventWindow.start|date('d.m.Y'), 'end': stats.eventWindow.end|date('d.m.Y')}) }}</p>
            {% endif %}
        </div>
        <div class="flex items-center gap-2 shrink-0">
            {{ ui.comparePicker(stats.compareEdition, stats.comparableEditions, edition.alias) }}
        </div>
    </div>

    {% if stats.isEmpty %}
        <div class="mt-12 text-center">
            <p class="text-base text-gray-500 dark:text-gray-400">{{ 'stats.empty.page'|trans }}</p>
        </div>
    {% else %}
        <div class="mt-6 flex flex-col gap-6">

            {# ── KPI strip ── #}
            <div class="grid grid-cols-2 md:grid-cols-5 gap-3">
                {% for k in stats.kpis %}
                    {{ ui.kpi(
                        k.label,
                        k.value,
                        k.suffix,
                        stats.compareDeltas[k.label] is defined ? stats.compareDeltas[k.label] : null,
                        k.suffix,
                        stats.compareEdition ? stats.compareEdition.name : null
                    ) }}
                {% endfor %}
            </div>

            {# ──────── Section: Anmeldungen ──────── #}
            {{ ui.section('stats.section.applications') }}

            <section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg" data-chart="daily-signups">
                <header class="px-5 pt-4 pb-3">
                    <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.daily.title'|trans }}</h3>
                    <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
                        {% if stats.appWindow %}
                            {{ 'stats.daily.subtitle'|trans({'start': stats.appWindow.start|date('d.m.Y'), 'end': stats.appWindow.end|date('d.m.Y')}) }}
                        {% else %}
                            {{ 'stats.daily.subtitle.noWindow'|trans }}
                        {% endif %}
                    </p>
                </header>
                <div class="p-5">
                    {{ ui.dailySignups(stats.daily) }}
                </div>
            </section>

            <section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg" data-chart="status-share">
                <header class="px-5 pt-4 pb-3">
                    <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.share.title'|trans }}</h3>
                    <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'stats.share.subtitle'|trans }}</p>
                </header>
                <div class="p-5">
                    {% if stats.applicationStatus.total > 0 %}
                        {{ ui.statusShare(stats.applicationStatus.segments, stats.applicationStatus.total, tones) }}
                    {% else %}{{ ui.empty() }}{% endif %}
                </div>
            </section>

            <div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
                <section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg" data-chart="status-funnel">
                    <header class="px-5 pt-4 pb-3">
                        <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.funnel.title'|trans }}</h3>
                        <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'stats.funnel.subtitle'|trans }}</p>
                    </header>
                    <div class="p-5">
                        {{ ui.funnel(stats.funnel, tones) }}
                    </div>
                </section>

<section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg" data-chart="confirmed-per-kid">
                    <header class="px-5 pt-4 pb-3">
                        <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.confirmedPerKid.title'|trans }}</h3>
                        <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'stats.confirmedPerKid.subtitle'|trans }}</p>
                    </header>
                    <div class="p-5">
                        {% if stats.confirmedPerKid|length %}
                            {% set rows = [] %}
                            {% for d in stats.confirmedPerKid %}{% set rows = rows|merge([{n: d.n, spots: d.spots, tone: d.spots == 0 ? 'rose' : 'emerald'}]) %}{% endfor %}
                            {{ ui.vbars(rows, tones, 'spots', 'emerald') }}
                            <div class="mt-2 text-center text-[10px] uppercase tracking-wider text-gray-400 dark:text-gray-500">{{ 'stats.confirmedPerKid.xAxis'|trans }}</div>
                        {% else %}{{ ui.empty() }}{% endif %}
                    </div>
                </section>
            </div>

            <section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg" data-chart="applied-vs-confirmed">
                <header class="px-5 pt-4 pb-3">
                    <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.appliedVsConfirmed.title'|trans }}</h3>
                    <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'stats.appliedVsConfirmed.subtitle'|trans }}</p>
                </header>
                <div class="p-5">
                    {% if stats.appliedPerKid|length or stats.confirmedPerKid|length %}
                        {{ ui.pairedKidHistogram(stats.appliedPerKid, stats.confirmedPerKid, tones) }}
                        <div class="mt-2 text-center text-[10px] uppercase tracking-wider text-gray-400 dark:text-gray-500">{{ 'stats.appliedVsConfirmed.xAxis'|trans }}</div>
                    {% else %}{{ ui.empty() }}{% endif %}
                </div>
            </section>

            {# ──────── Section: Anmeldeverhalten ──────── #}
            {{ ui.section('stats.section.behaviour') }}

            <section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg" data-chart="registration-hours">
                <header class="px-5 pt-4 pb-3">
                    <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.hours.title'|trans }}</h3>
                    <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'stats.hours.subtitle'|trans }}</p>
                </header>
                <div class="p-5">
                    {{ ui.hourHistogram(stats.registrationHours, tones) }}
                    <div class="mt-2 text-center text-[10px] uppercase tracking-wider text-gray-400 dark:text-gray-500">{{ 'stats.hours.xAxis'|trans }}</div>
                </div>
            </section>

            {# ──────── Section: Teilnehmende ──────── #}
            {{ ui.section('stats.section.participants') }}

            <div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
                <section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg" data-chart="age-histogram">
                    <header class="px-5 pt-4 pb-3">
                        <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.age.title'|trans }}</h3>
                        <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'stats.age.subtitle'|trans }}</p>
                    </header>
                    <div class="p-5">
                        {% if stats.ages|length %}{{ ui.vbars(stats.ages, tones, 'age', 'indigo') }}{% else %}{{ ui.empty() }}{% endif %}
                    </div>
                </section>
                <section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg lg:col-span-2" data-chart="category-fit">
                    <header class="px-5 pt-4 pb-3">
                        <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.categories.title'|trans }}</h3>
                        <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'stats.categories.subtitle'|trans }}</p>
                    </header>
                    <div class="p-5">
                        {% if stats.categories|length %}{{ ui.barList(stats.categories, tones) }}{% else %}{{ ui.empty() }}{% endif %}
                    </div>
                </section>
            </div>

            <div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
                <section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg" data-chart="new-vs-returning">
                    <header class="px-5 pt-4 pb-3">
                        <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.family.title'|trans }}</h3>
                        <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'stats.family.subtitle'|trans }}</p>
                    </header>
                    <div class="p-5">
                        {% if stats.newVsReturning.total > 0 %}
                            {{ ui.statusShare(stats.newVsReturning.segments, stats.newVsReturning.total, tones) }}
                        {% else %}{{ ui.empty() }}{% endif %}
                    </div>
                </section>
                <section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg" data-chart="plz-distribution">
                    <header class="px-5 pt-4 pb-3">
                        <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.plz.title'|trans }}</h3>
                        <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'stats.plz.subtitle'|trans }}</p>
                    </header>
                    <div class="p-5">
                        {% if stats.plzDistribution|length %}{{ ui.simpleBarList(stats.plzDistribution, tones) }}{% else %}{{ ui.empty() }}{% endif %}
                    </div>
                </section>
            </div>

            {# ──────── Section: Angebote ──────── #}
            {{ ui.section('stats.section.offers') }}

            <div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
                <section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg" data-chart="top-offers">
                    <header class="px-5 pt-4 pb-3">
                        <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.topOffers.title'|trans }}</h3>
                        <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'stats.topOffers.subtitle'|trans }}</p>
                    </header>
                    <div class="p-5">
                        {% if stats.topOffers|length %}{{ ui.barList(stats.topOffers, tones) }}{% else %}{{ ui.empty() }}{% endif %}
                    </div>
                </section>
                <section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg" data-chart="flop-offers">
                    <header class="px-5 pt-4 pb-3">
                        <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.flopOffers.title'|trans }}</h3>
                        <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'stats.flopOffers.subtitle'|trans }}</p>
                    </header>
                    <div class="p-5">
                        {% if stats.flopOffers|length %}{{ ui.barList(stats.flopOffers, tones) }}{% else %}{{ ui.empty() }}{% endif %}
                    </div>
                </section>
            </div>

            <div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
                <section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg" data-chart="utilization-histogram">
                    <header class="px-5 pt-4 pb-3">
                        <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.utilization.title'|trans }}</h3>
                        <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'stats.utilization.subtitle'|trans }}</p>
                    </header>
                    <div class="p-5">
                        {{ ui.vbars(stats.utilization, tones, 'bucket', 'indigo') }}
                    </div>
                </section>
                <section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg lg:col-span-2" data-chart="top-vendors">
                    <header class="px-5 pt-4 pb-3">
                        <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.topVendors.title'|trans }}</h3>
                        <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'stats.topVendors.subtitle'|trans }}</p>
                    </header>
                    <div class="p-5">
                        {% if stats.topVendors|length %}{{ ui.topVendors(stats.topVendors) }}{% else %}{{ ui.empty() }}{% endif %}
                    </div>
                </section>
            </div>

            {# ──────── Section: Operativ & Zahlung ──────── #}
            {{ ui.section('stats.section.operational') }}

            <div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
                <section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg" data-chart="price-distribution">
                    <header class="px-5 pt-4 pb-3">
                        <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.price.title'|trans }}</h3>
                        <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'stats.price.subtitle'|trans }}</p>
                    </header>
                    <div class="p-5">
                        {{ ui.denseHistogram(stats.priceDistribution, tones) }}
                    </div>
                </section>
<section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg" data-chart="payment-timing">
                    <header class="px-5 pt-4 pb-3">
                        <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.payment.title'|trans }}</h3>
                        <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'stats.payment.subtitle'|trans }}</p>
                    </header>
                    <div class="p-5">
                        {{ ui.denseHistogram(stats.paymentTiming, tones) }}
                        <div class="mt-2 text-center text-[10px] uppercase tracking-wider text-gray-400 dark:text-gray-500">{{ 'stats.payment.xAxis'|trans }}</div>
                    </div>
                </section>
            </div>

            <section class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-white/5 rounded-lg" data-chart="cancellation-timing">
                <header class="px-5 pt-4 pb-3">
                    <h3 class="text-sm font-bold text-gray-900 dark:text-gray-50">{{ 'stats.cancel.title'|trans }}</h3>
                    <p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">{{ 'stats.cancel.subtitle'|trans }}</p>
                </header>
                <div class="p-5">
                    {{ ui.denseHistogram(stats.cancellationTiming, tones) }}
                </div>
            </section>

        </div>
    {% endif %}
{% endblock %}
