"use client"; /** * "NEW · last 15 min" (server-26#238). The rail is worst-first, so a fresh * minor that is escalating sits under stale Majors; this lane is the * recency view of the same FILTERED incidents, newest first, with why each * one is here ("New", "↑ Major", "+1 stop", a priority keyword). * * Desktop: overlay at the map's top-left, right of the zoom stack and above * MapView's rail (the rail starts at top-[9.5rem], so the lane is capped * just short of it and its rows scroll). The Gate A notice is pinned below * the rows, never inside the scroll area — same rule as the rail (#46). * Mobile: a compact chip under MapView's centred "Live" chip (same top-3 * centre slot would cover it), right of the fit-all button; it expands. * Hidden when there is nothing new. */ import { useState } from "react"; import type { LaneEntry } from "@/lib/attention"; import { SEVERITY_COLORS, isKnownSeverity } from "@/lib/severity"; import { MachineOutputNotice } from "@/components/ui/MachineOutputNotice"; function ago(at: number, now: number): string { const m = Math.max(0, Math.floor((now - at) / 60_000)); return m < 1 ? "now" : `${m}m`; } function Row({ e, now, onSelect }: { e: LaneEntry; now: number; onSelect: (id: string) => void }) { const color = isKnownSeverity(e.severity) ? SEVERITY_COLORS[e.severity] : "var(--ink-muted)"; const body = ( <>