export interface ProcessSankeyNode {
    id: string;
    /** Optional explicit lifetime bound [start, end]. Lifetime is
     *  `min(xExtent[0], earliestEdge)` to `max(xExtent[1], latestEdge)`. */
    xExtent?: [number, number];
}
export interface ProcessSankeyEdge {
    id: string;
    source: string;
    target: string;
    value: number;
    startTime: number;
    endTime: number;
    /** Optional: time at which this unit of mass actually "arrived" at
     *  the SOURCE node (e.g., the hospital admit time for an ER patient
     *  whose transfer to ICU happens later at `startTime`). Purely a
     *  rendering hint — the layout/mass profile is unchanged. The
     *  renderer cuts a rectangular slot out of the source node's band
     *  from the node's left edge up to the scaled `systemInTime`, with
     *  height equal to this edge's ribbon thickness. Edges without
     *  `systemInTime` are drawn as-is. Result: a staircase profile on
     *  the source side as units enter the system one by one.
     *  Default: undefined. */
    systemInTime?: number;
    /** Optional: time at which this unit of mass leaves the TARGET node
     *  (e.g., the discharge time for a patient who arrived at the ward
     *  at `endTime`). Symmetric to `systemInTime`: the renderer cuts a
     *  rectangular slot out of the target node's band from the scaled
     *  `systemOutTime` to the node's right edge, with height equal to
     *  this edge's ribbon thickness. Layout/mass profile unchanged.
     *  Default: undefined. */
    systemOutTime?: number;
}
export interface ProcessSankeyIssue {
    kind: string;
    id?: string;
    source?: string;
    target?: string;
    endpoint?: string;
    nodeId?: string;
}
export interface ProcessSankeySample {
    t: number;
    topMass: number;
    botMass: number;
}
export type AttachmentSide = "top" | "bot";
export type AttachmentKind = "in" | "out";
export interface ProcessSankeyAttachment {
    side: AttachmentSide;
    time: number;
    sideMassBefore: number;
    sideMassAfter: number;
    kind: AttachmentKind;
    value: number;
}
export interface ProcessSankeyNodeData {
    samples: ProcessSankeySample[];
    peak: number;
    topPeak: number;
    botPeak: number;
    localAttachments: Map<string, ProcessSankeyAttachment>;
}
export interface ProcessSankeySlotPeak {
    topPeak: number;
    botPeak: number;
}
export interface ProcessSankeySlotOccupant {
    id: string;
    end: number;
}
export interface ProcessSankeySlot {
    peak: ProcessSankeySlotPeak;
    occupants: ProcessSankeySlotOccupant[];
}
export interface ProcessSankeyLaneLifetime {
    start: number | null;
    end: number | null;
}
export interface ProcessSankeySideRecord {
    sourceSide?: AttachmentSide;
    targetSide?: AttachmentSide;
}
export interface ProcessSankeyLayout {
    nodeData: Record<string, ProcessSankeyNodeData>;
    sides: Map<string, ProcessSankeySideRecord>;
    valueScale: number;
    padding: number;
    compressedPadding: boolean;
    centerlines: Record<string, number>;
    laneLifetime: Record<string, ProcessSankeyLaneLifetime>;
    slots: ProcessSankeySlot[];
    slotByNode: Record<string, number>;
    crossingsBefore: number | null;
    crossingsAfter: number | null;
    lengthBefore: number | null;
    lengthAfter: number | null;
}
export interface ProcessSankeyOptions {
    plotH: number;
    pairing?: "value" | "temporal";
    packing?: "off" | "reuse";
    laneOrder?: "insertion" | "crossing-min" | "inside-out" | "crossing-min+inside-out";
    lifetimeMode?: "full" | "half";
}
export interface ProcessSankeyEdgeIndex {
    incoming: Record<string, ProcessSankeyEdge[]>;
    outgoing: Record<string, ProcessSankeyEdge[]>;
}
type Domain = [number, number] | null | undefined;
export declare function validateProcessSankey(nodes: ProcessSankeyNode[], edges: ProcessSankeyEdge[], domain: [number, number]): ProcessSankeyIssue[];
export declare function formatProcessSankeyIssue(issue: ProcessSankeyIssue): string;
export declare function buildEdgeIndex(nodes: ProcessSankeyNode[], edges: ProcessSankeyEdge[]): ProcessSankeyEdgeIndex;
export declare function assignSides(nodes: ProcessSankeyNode[], edges: ProcessSankeyEdge[], edgeIndex: ProcessSankeyEdgeIndex, pairing?: "value" | "temporal"): Map<string, ProcessSankeySideRecord>;
export declare function computeNode(node: ProcessSankeyNode, edgeIndex: ProcessSankeyEdgeIndex, sides: Map<string, ProcessSankeySideRecord>): ProcessSankeyNodeData;
export declare function clampTime(t: number, domain: Domain): number;
export declare function clampSamples(samples: ProcessSankeySample[], domain: Domain): ProcessSankeySample[];
export declare function attachmentYRange(att: ProcessSankeyAttachment, cl: number, S: number): [number, number];
export declare function buildBandPath(samples: ProcessSankeySample[], cl: number, S: number, xScale: (t: number) => number, domain: Domain): string | null;
/**
 * One 20-px gradient stub at an attachment with `systemInTime` /
 * `systemOutTime`. Rendered as its own bezier scene-edge with a
 * horizontal gradient, painted underneath the band. The band
 * paints with `fill: none` whenever any stubs are present, so the
 * stub gradients are the only colored regions inside the band's
 * outline.
 */
export interface BandGradientStub {
    /** Rect path (M-L-L-L-Z). */
    pathD: string;
    /** Gradient extent in screen pixels. */
    x0: number;
    x1: number;
    /** Color stops — 0 = transparent end, 1 = band-color end. */
    from: 0 | 1;
    to: 0 | 1;
}
/**
 * Build the per-edge 20-px gradient stubs that visualize
 * `systemInTime` / `systemOutTime` on a node band. Each stub is
 * a rect on the edge's attachment slot, painted with a horizontal
 * gradient that fades the band color in (or out) over 20 screen
 * pixels and saturates through the rest of the rect.
 *
 * The rect is clipped to the band's outline bounds (so cutouts don't
 * spill outside the node shape), but the gradient extent stays at
 * its natural `[xSysIn - FADE_PX, xSysIn]` / `[xSysOut, xSysOut + FADE_PX]`
 * range. The canvas renderer uses pad-mode clamping for color stops
 * outside the rect, so a stub whose fade region falls past the band's
 * edge still paints solid band-color where it's visible — instead of
 * collapsing to a degenerate gradient that the renderer would clamp
 * to transparent.
 *
 * Pure rendering hint — layout/mass-profile unchanged. Returns an
 * empty array when the node has no qualifying edges.
 */
export declare function buildBandCutoutsForNode(nodeId: string, edges: ProcessSankeyEdge[], layout: ProcessSankeyLayout, xScale: (t: number) => number, domain: Domain): BandGradientStub[];
type SlotByNode = Record<string, number>;
export declare function countCrossings(slotByNode: SlotByNode, edges: ProcessSankeyEdge[]): number;
export declare function totalEdgeLength(slotByNode: SlotByNode, edges: ProcessSankeyEdge[]): number;
interface LaneLayoutOptions {
    plotH: number;
    padding: number;
    valueScale: number;
    packing?: "off" | "reuse";
    laneOrder?: "insertion" | "crossing-min" | "inside-out" | "crossing-min+inside-out";
    lifetimeMode?: "full" | "half";
}
interface LaneLayoutResult {
    effectiveSlotsHeight: number;
    centerlines: Record<string, number>;
    laneLifetime: Record<string, ProcessSankeyLaneLifetime>;
    slots: ProcessSankeySlot[];
    slotByNode: SlotByNode;
    slotCenter: number[];
    crossingsBefore: number | null;
    crossingsAfter: number | null;
    lengthBefore: number | null;
    lengthAfter: number | null;
}
export declare function computeLaneLayout(nodes: ProcessSankeyNode[], edges: ProcessSankeyEdge[], nodeData: Record<string, ProcessSankeyNodeData>, edgeIndex: ProcessSankeyEdgeIndex, opts: LaneLayoutOptions): LaneLayoutResult;
/**
 * Compute the full Process Sankey layout for a given dataset and
 * configuration. Pure function, no side effects.
 *
 * The chart's time domain isn't a layout opt — domain handling lives
 * in the geometry helpers (`buildBandPath`, `buildRibbonGeometry`,
 * `clampSamples`) which receive an `xScale` and a domain pair from
 * the caller. The layout itself is timeless apart from the per-node
 * sample/event timestamps.
 */
export declare function computeProcessSankeyLayout(nodes: ProcessSankeyNode[], edges: ProcessSankeyEdge[], opts: ProcessSankeyOptions): ProcessSankeyLayout;
export {};
