@props([
    /** @var array<int, int|float|null> the series, in the order it happened */
    'points' => [],
    // muted where the figure is observed, accent where it can be acted on.
    // Four accent charts in a row is how an accent stops meaning anything.
    'tone' => 'accent',
    'area' => false,
    /*
    | The scale. Left null, the line stretches over its own smallest and largest
    | value — the classic sparkline, and the right choice when the question is
    | "what shape did this take".
    |
    | It is the WRONG choice when the question is "how busy is this", and the
    | host page proved it: a machine sitting at 0.2 % CPU, wobbling between 0.1
    | and 0.3, drew a seismograph and flatly contradicted the figure printed
    | beside it. Passing min=0 (and max=100 for a percentage) anchors the box so
    | a calm host looks calm — the same rule the Chart.js version already
    | carried as "an auto-scaled axis makes 3 % look like a wall of load".
    */
    'min' => null,
    'max' => null,
    // Rendered size in px. The viewBox stays 96×34, so this only stretches.
    'width' => 80,
    'height' => 32,
])
@php
    /*
    | A missing sample BREAKS the line; it is not filtered out.
    |
    | This used to start with array_filter(…, 'is_numeric'), which threw the
    | gaps away and joined their neighbours. Two things went wrong at once: the
    | line claimed a measurement that was never taken, and every point after
    | the gap slid left — an hour of samples with two gaps drew itself as
    | fifty-eight minutes and put the newest reading somewhere in the middle.
    |
    | The x position is therefore taken from the point's place in the ORIGINAL
    | series, and consecutive readings are collected into segments that are
    | drawn as separate paths. A series with nothing missing yields exactly one
    | segment and the same picture as before — which is what every existing
    | caller passes.
    */
    $values = array_values($points);
    $numeric = array_values(array_filter($values, 'is_numeric'));

    $low = $min ?? ($numeric ? min($numeric) : 0);
    $high = $max ?? ($numeric ? max($numeric) : 0);
    $span = max(0.0001, $high - $low);
    $step = count($values) > 1 ? 96 / (count($values) - 1) : 96;

    $segments = [];
    $current = [];

    foreach ($values as $i => $v) {
        if (! is_numeric($v)) {
            // A single reading on its own cannot be a line; it ends the segment
            // without drawing one, rather than emitting a path of one point.
            if (count($current) > 1) {
                $segments[] = $current;
            }
            $current = [];

            continue;
        }

        // Clamped: a value outside the given bounds belongs at the edge, not
        // outside the box where it would be clipped into a straight line.
        $ratio = min(1, max(0, ((float) $v - $low) / $span));
        $current[] = [round($i * $step, 1), round(30 - $ratio * 26, 1)];
    }

    if (count($current) > 1) {
        $segments[] = $current;
    }

    // Nur die Koordinaten, ohne Befehlsbuchstaben — der Aufrufer setzt das `M`
    // oder das `L` davor. Vorher trug diese Funktion ihr `M` selbst, und im
    // Flächenpfad stand damit `… L` unmittelbar vor einem `M`: gültig gelesen,
    // nicht gezeichnet, und die Füllung verschwand ohne eine einzige Meldung.
    $coords = fn (array $seg) => implode(' ', array_map(fn ($p) => $p[0].' '.$p[1], $seg));

    // Own id per render: two gradients sharing one would be harmless, but a
    // fill referring to a def that a later render replaced would not.
    $fade = 'spark-fade-'.substr(md5($tone.serialize($values).$width), 0, 10);
@endphp
@if ($segments !== [])
    <svg class="spark {{ $tone === 'accent' ? '' : 'muted' }}" viewBox="0 0 96 34" preserveAspectRatio="none"
         style="width:{{ (int) $width }}px;height:{{ (int) $height }}px" aria-hidden="true">
        @if ($area)
            {{-- A fade rather than a flat tint: the fill carries the eye down to
                 the baseline instead of ending in a hard edge halfway up. --}}
            <defs>
                <linearGradient id="{{ $fade }}" x1="0" y1="0" x2="0" y2="1">
                    <stop offset="0%" stop-color="currentColor" stop-opacity=".22" />
                    <stop offset="100%" stop-color="currentColor" stop-opacity="0" />
                </linearGradient>
            </defs>
        @endif
        @foreach ($segments as $seg)
            @if ($area)
                {{-- Closed to the baseline under ITS OWN span, not under the whole
                     box: an area that ran from 0 to 96 would fill the gaps the
                     line above deliberately leaves open. --}}
                <path class="area" fill="url(#{{ $fade }})" d="M{{ $seg[0][0] }} 34 L{{ $coords($seg) }} L{{ end($seg)[0] }} 34 Z" />
            @endif
            <path class="line" d="M{{ $coords($seg) }}" />
        @endforeach
    </svg>
@endif
