/**
 * UILayoutDebugger
 *
 * A development-only utility for visualizing and debugging the UIView layout
 * system. Disabled entirely at runtime unless explicitly enabled.
 *
 * FEATURES
 * ─────────
 *
 * 1. Record-and-replay step debugger
 *    Every layout pass is recorded as an ordered sequence of steps. Each step
 *    captures the view that was laid out, its frame before and after, and the
 *    frames assigned to each of its subviews. After the pass completes you can
 *    scrub through the steps one at a time in the overlay UI, seeing exactly
 *    which view was processed at each point and how the frames changed.
 *
 * 2. Live breakpoint step-through
 *    When breakpoint mode is enabled (UILayoutDebugger.enableBreakpoints()), a
 *    special sentinel line is executed before each view's layoutIfNeeded() call.
 *    Put a browser debugger breakpoint on that line and the JS debugger will
 *    pause before every layout step — the full live JS stack and all object
 *    state are available at that point, exactly as with any other breakpoint.
 *
 *    The sentinel line is:
 *      const breakpointOnThisLine = "Add a breakpoint on this line to step through layout."
 *    Search for that string in the Sources panel to find it quickly.
 *
 * 3. View-tree heat-map overlay
 *    A floating panel renders the full view hierarchy as an indented tree.
 *    Each node is coloured by how many times it was laid out in the most recent
 *    pass: untouched (grey), once (green), twice (orange), three-or-more (red).
 *    The node currently active in the step scrubber is highlighted in blue.
 *    Hovering a node shows its class, elementID, and frame.
 *
 * INTEGRATION POINTS IN UIView.ts
 * ────────────────────────────────
 * Add the following calls alongside the existing UILayoutCycleTracer calls:
 *
 *   layoutViewsIfNeeded():
 *     window.UILayoutDebugger?.willBeginLayoutPass(UIView._viewsToLayout)    // before the while loop
 *     window.UILayoutDebugger?.willBeginIteration(iteration)                 // inside the while loop, top
 *     window.UILayoutDebugger?.willLayoutView(view)                          // before view.layoutIfNeeded()
 *     [breakpoint sentinel — see below]
 *     view.layoutIfNeeded()
 *     window.UILayoutDebugger?.didLayoutView(view)                           // after view.layoutIfNeeded()
 *     window.UILayoutDebugger?.didFinishLayoutPass(iteration)                // after the while loop
 *
 *   layoutSubviews():
 *     window.UILayoutDebugger?.willSetSubviewFrames(this)                    // before the subview loop
 *     [existing subview loop]
 *     window.UILayoutDebugger?.didSetSubviewFrames(this)                     // after the subview loop
 *
 *   The breakpoint sentinel block (inside layoutViewsIfNeeded, before
 *   view.layoutIfNeeded()):
 *
 *     if (window.UILayoutDebugger?._shouldHitBreakpoint(view)) {
 *         const breakpointOnThisLine = "Add a breakpoint on this line to step through layout."
 *     }
 *
 * USAGE
 * ─────
 *   UILayoutDebugger.enable()            — record traces and show the overlay
 *   UILayoutDebugger.disable()           — hide overlay and stop recording
 *   UILayoutDebugger.enableBreakpoints() — also pause at each layout step
 *   UILayoutDebugger.stepForward()       — advance the replay scrubber by one
 *   UILayoutDebugger.stepBack()          — retreat the replay scrubber by one
 *   UILayoutDebugger.goToStep(n)         — jump to step n (0-based)
 */
interface UILayoutDebugFrame {
    top: number;
    left: number;
    width: number;
    height: number;
}
/** A snapshot of a view's intrinsic size cache at a point in time. */
interface UILayoutDebugCacheSnapshot {
    entryCount: number;
    entries: Record<string, {
        width: number;
        height: number;
    }>;
    isShared: boolean;
    sharedKey?: string;
    /** Whether _frameCache was populated at snapshot time. */
    hasFrameCache: boolean;
    /** Snapshot of _frameCache if populated; null if absent. */
    frameCache: UILayoutDebugFrame | null;
    /** Whether _frameCacheForVirtualLayouting was populated at snapshot time. */
    hasVirtualFrameCache: boolean;
    /** Snapshot of _frameCacheForVirtualLayouting if populated; null if absent. */
    virtualFrameCache: UILayoutDebugFrame | null;
}
/**
 * Global UITextMeasurement cache sizes at a snapshot instant.
 * These are not per-view — they're attached to the snapshot as a whole.
 */
interface UILayoutDebugTextMeasurementSnapshot {
    preparedCacheSize: number;
    styleCacheSize: number;
}
interface UILayoutDebugSubviewRecord {
    viewIndex: number;
    className: string;
    elementID: string;
    frameBefore: UILayoutDebugFrame | null;
    frameAfter: UILayoutDebugFrame | null;
}
/** What caused a view to enter the layout queue. */
interface UILayoutDebugTrigger {
    callerFunction: string;
    cleanStack: string;
}
/** One step = one call to layoutIfNeeded() on one view. */
interface UILayoutDebugStep {
    stepIndex: number;
    iteration: number;
    viewIndex: number;
    className: string;
    elementID: string;
    frameBefore: UILayoutDebugFrame | null;
    frameAfter: UILayoutDebugFrame | null;
    cacheBefore: UILayoutDebugCacheSnapshot | null;
    cacheAfter: UILayoutDebugCacheSnapshot | null;
    subviewRecords: UILayoutDebugSubviewRecord[];
    trigger: UILayoutDebugTrigger | null;
}
interface UILayoutDebugTreeNode {
    viewIndex: number;
    className: string;
    elementID: string;
    depth: number;
    frame: UILayoutDebugFrame | null;
    layoutCount: number;
    cacheAfterPass: UILayoutDebugCacheSnapshot | null;
    children: UILayoutDebugTreeNode[];
}
interface UILayoutDebugTrace {
    passIndex: number;
    steps: UILayoutDebugStep[];
    roots: UILayoutDebugTreeNode[];
    totalIterations: number;
    cacheChanges: UILayoutDebugCacheChangeEvent[];
}
/** A flat snapshot of every view's frame and intrinsic cache at a point in time. */
interface UILayoutDebugStateSnapshot {
    label: string;
    takenAt: number;
    views: Map<number, UILayoutDebugViewState>;
    /** Global UITextMeasurement cache sizes at the instant this snapshot was taken. */
    textMeasurement: UILayoutDebugTextMeasurementSnapshot;
}
interface UILayoutDebugViewState {
    viewIndex: number;
    className: string;
    elementID: string;
    frame: UILayoutDebugFrame | null;
    cache: UILayoutDebugCacheSnapshot | null;
}
type UILayoutDebugDiffKind = "appeared" | "disappeared" | "frame" | "cache" | "both" | "unchanged";
interface UILayoutDebugViewDiff {
    kind: UILayoutDebugDiffKind;
    viewIndex: number;
    className: string;
    elementID: string;
    baselineFrame: UILayoutDebugFrame | null;
    currentFrame: UILayoutDebugFrame | null;
    baselineCache: UILayoutDebugCacheSnapshot | null;
    currentCache: UILayoutDebugCacheSnapshot | null;
}
/**
 * Fired when _getCachedIntrinsicSize returns a value that differs from the
 * last value we observed for that view+cacheKey combination.
 */
interface UILayoutDebugCacheChangeEvent {
    eventIndex: number;
    stepIndex: number;
    iteration: number;
    viewIndex: number;
    className: string;
    elementID: string;
    cacheKey: string;
    newValue: {
        width: number;
        height: number;
    };
    callerFunction: string;
    cleanStack: string;
}
export declare class UILayoutDebugger {
    static _isEnabled: boolean;
    static _breakpointsEnabled: boolean;
    static get isEnabled(): boolean;
    static get breakpointsEnabled(): boolean;
    static _passIndex: number;
    static _currentTrace: UILayoutDebugTrace | null;
    static _currentIteration: number;
    static _pendingStep: UILayoutDebugStep | null;
    static _pendingSubviewsBefore: Map<number, UILayoutDebugFrame | null>;
    static _layoutCountsThisPass: Map<number, number>;
    static _liveViewRegistry: Map<number, any>;
    static _triggerMap: Map<number, UILayoutDebugTrigger>;
    static _noiseFramePrefixes: string[];
    static _traces: UILayoutDebugTrace[];
    static readonly maxStoredTraces = 20;
    static _replayTraceIndex: number;
    static _replayStepIndex: number;
    static _compareMode: boolean;
    static _frameFilter: "all" | "changed" | "unchanged";
    /**
     * When true, frame comparisons ignore origin (x/y) and only consider size
     * (width/height) — i.e. they diff bounds rather than frames.
     * A position-only move does not trigger a layout recompute of content, so
     * bounds mode surfaces only the changes that actually matter for sizing.
     */
    static _boundsBasedDiff: boolean;
    static _compareTraceIndex: number;
    static _compareStepIndex: number;
    static _sharedExpandState: Map<number, boolean>;
    static _singleExpandState: Map<number, boolean>;
    static _liveExpandState: Map<number, boolean>;
    static enable(): void;
    static disable(): void;
    /**
     * Enable the breakpoint sentinel. Once enabled, _shouldHitBreakpoint()
     * returns true before every layoutIfNeeded() call so the browser debugger
     * can pause on the sentinel line in UIView.ts.
     */
    static enableBreakpoints(): void;
    static disableBreakpoints(): void;
    static stepForward(): void;
    static stepBack(): void;
    static goToStep(stepIndex: number): void;
    static goToCompareStep(stepIndex: number): void;
    static showTrace(traceIndex: number): void;
    static showCompareTrace(traceIndex: number): void;
    static get _currentReplayTrace(): UILayoutDebugTrace | null;
    static get _currentCompareTrace(): UILayoutDebugTrace | null;
    static willBeginLayoutPass(viewsToLayout: any[]): void;
    static willBeginIteration(iteration: number): void;
    /**
     * Called from setNeedsLayout() each time a view is enqueued.
     * Only the *first* enqueue per view per pass is recorded — that is the
     * call that actually caused the view to enter the queue. Subsequent calls
     * on the same view within the same pass are redundant and ignored.
     */
    static viewDidCallSetNeedsLayout(view: any): void;
    /**
     * Called from _setCachedIntrinsicSize() after the value is written.
     * Every write is a change by definition, so no history comparison is needed.
     *
     * Call site in UIView.ts, at the end of _setCachedIntrinsicSize():
     *
     *   window.UILayoutDebugger?.didSetCachedIntrinsicSize(this, cacheKey, size)
     */
    static didSetCachedIntrinsicSize(view: any, cacheKey: string, value: any): void;
    static willLayoutView(view: any): void;
    /**
     * Called immediately after view.layoutIfNeeded(). Closes the pending step
     * with the post-layout frame.
     */
    static didLayoutView(view: any): void;
    static didFinishLayoutPass(iterationCount: number): void;
    /** Discard all recorded traces and reset the replay state. */
    static clearTraces(): void;
    /** Capture the current view tree state as the baseline for future diffs. */
    static captureBaseline(): void;
    /** Capture the current state and diff it against the baseline. */
    static captureAndDiff(): void;
    static clearDiff(): void;
    /**
     * ☢  Stale Layout Report
     *
     * The single authoritative way to discover missing cache invalidations.
     *
     * What this does, in order:
     *   1. Snapshots every view's frame and intrinsic cache right now (the
     *      "before" state — potentially stale/incorrect).
     *   2. Calls performForcedSubtreeLayout() on the root view, which nukes all
     *      caches and forces a complete cold remeasure of the entire tree.
     *   3. Snapshots again ("after" state — ground truth).
     *   4. Diffs the two snapshots.  Any view that changed between before and
     *      after had stale state that was never correctly invalidated.
     *   5. For each changed view, cross-references the cache writes from the
     *      forced pass so you can see exactly which call path recomputed the
     *      correct value — working backwards from that to find the missing
     *      invalidation site.
     *
     * The result is shown in the ☢ Stale panel to the right of the pass
     * inspector.  Views corrected by the forced pass are also tinted amber in
     * the pass inspector tree on the subsequent pass.
     *
     * Limitations:
     *   - Calls performForcedSubtreeLayout(), which is itself a nuclear option.
     *     The tree will be left in its corrected state — not the buggy state.
     *     Use this at the point where the bug is visible, not before.
     *   - The forced layout will generate a new trace (the remeasure pass).
     *     The ☢ panel cross-references its cache writes automatically.
     *   - Only intrinsic-size cache corrections are cross-referenced. Frame
     *     corrections are shown as diffs but do not yet have a write-stack.
     */
    static captureStaleLayoutReport(): void;
    static clearStaleReport(): void;
    static toggleLiveInspector(): void;
    static _captureStateSnapshot(label: string): UILayoutDebugStateSnapshot | null;
    /**
     * Like _captureStateSnapshot but walks from an explicit root rather than
     * _lastKnownRootView. Use this whenever the root must be pinned across a
     * call that may update _lastKnownRootView (e.g. captureStaleLayoutReport,
     * which drives a layout pass internally).
     */
    static _captureStateSnapshotFromRoot(rootView: any, label: string): UILayoutDebugStateSnapshot;
    static _walkViewTree(view: any, out: Map<number, UILayoutDebugViewState>, visited: Set<number>): void;
    static _diffSnapshots(baseline: UILayoutDebugStateSnapshot, current: UILayoutDebugStateSnapshot): UILayoutDebugViewDiff[];
    static _framesEqual(a: UILayoutDebugFrame | null, b: UILayoutDebugFrame | null): boolean;
    static _cachesEqual(a: UILayoutDebugCacheSnapshot | null, b: UILayoutDebugCacheSnapshot | null): boolean;
    /**
     * Called at the top of layoutSubviews(), before the subview frame loop.
     * Nothing to do here — before-frames were already captured in willLayoutView().
     */
    static willSetSubviewFrames(_view: any): void;
    /**
     * Called at the bottom of layoutSubviews(), after the subview frame loop.
     * Merges the before/after subview frames into the pending step.
     */
    static didSetSubviewFrames(view: any): void;
    /**
     * Returns true when breakpoints are enabled, causing the sentinel block
     * in UIView.ts to execute. Put a browser debugger breakpoint on the
     * `const breakpointOnThisLine` assignment inside that block.
     */
    static _shouldHitBreakpoint(_view: any): boolean;
    static _cleanStack(rawStack: string): string;
    static _extractCallerFunctionName(cleanStack: string): string;
    static _captureFrame(view: any): UILayoutDebugFrame | null;
    static _captureCache(view: any): UILayoutDebugCacheSnapshot | null;
    static _buildTreeSnapshot(view: any, depth: number, visited?: Set<number>): UILayoutDebugTreeNode;
    static _baseline: UILayoutDebugStateSnapshot | null;
    static _diffSnapshot: UILayoutDebugStateSnapshot | null;
    static _diffMode: boolean;
    static _liveInspectorMode: boolean;
    /** Result of the last captureStaleLayoutReport() run. */
    static _staleReportResult: {
        before: UILayoutDebugStateSnapshot;
        after: UILayoutDebugStateSnapshot;
        diffs: UILayoutDebugViewDiff[];
        /** viewIndex → cacheChanges from the forced-layout pass, for cross-referencing */
        forcedPassCacheChanges: Map<number, UILayoutDebugCacheChangeEvent[]>;
        passIndex: number;
    } | null;
    /** Whether the stale report side-panel is open. */
    static _staleReportMode: boolean;
    static _lastKnownRootView: any;
    /**
     * Finds the first trace (chronologically) recorded after baselineTakenAt
     * that contains a step for the given viewIndex. Returns {traceIndex, stepIndex}
     * into _traces, or null if none found.
     */
    static _findCausingTrace(viewIndex: number, baselineTakenAt: number): {
        traceIndex: number;
        stepIndex: number;
        passIndex: number;
    } | null;
    static _overlayRoot: HTMLElement | null;
    static _overlayVisible: boolean;
    static _helpMode: boolean;
    static _ensureOverlay(): void;
    static _removeOverlay(): void;
    static _renderOverlay(): void;
    static _renderPassColumn(traceIndex: number, stepIndex: number, onStepChange: (si: number) => void, onTraceChange: (ti: number) => void, expandState: Map<number, boolean> | null, registerTree: (el: HTMLElement) => void, getPeerTree: () => HTMLElement | null): HTMLElement;
    static _renderStaleReportPanel(result: NonNullable<typeof UILayoutDebugger._staleReportResult>): HTMLElement;
    static _renderHelpPanel(): HTMLElement;
    static _renderLiveInspectorPanel(): HTMLElement;
    static _renderLiveNode(view: any, container: HTMLElement, depth: number, visited: Set<number>, expandState: Map<number, boolean>): void;
    static _renderDiffPanel(baseline: UILayoutDebugStateSnapshot, current: UILayoutDebugStateSnapshot, onNavigate: (viewIndex: number) => void, baselineTakenAt: number): HTMLElement;
    static _renderStepDetail(activeStep: UILayoutDebugStep): HTMLElement;
    static _subtreeHasTouched(node: UILayoutDebugTreeNode, countMap: Map<number, number>): boolean;
    static _subtreeContains(node: UILayoutDebugTreeNode, viewIndex: number): boolean;
    static _renderTreeNode(node: UILayoutDebugTreeNode, container: HTMLElement, countMap: Map<number, number>, activeViewIndex: number, expandState: Map<number, boolean> | null, stepMap: Map<number, UILayoutDebugStep>): HTMLElement | null;
    static _formatFrame(f: UILayoutDebugFrame | null): string;
    static _formatFrameDiff(before: UILayoutDebugFrame | null, after: UILayoutDebugFrame | null): string;
    static _formatCacheSnapshot(c: UILayoutDebugCacheSnapshot | null): string;
    static _formatCacheDiff(before: UILayoutDebugCacheSnapshot | null, after: UILayoutDebugCacheSnapshot | null): string;
    static _heatColor(count: number): string;
    static _el(tag: string, styles: string[]): HTMLElement;
    static _btnStyle(color: string): string[];
    static _makeDraggable(panel: HTMLElement): void;
}
declare global {
    interface Window {
        UILayoutDebugger?: typeof UILayoutDebugger;
    }
}
export {};
