/* RxBlazorV2.MudBlazor — Swipeout + Sortable
 *
 * Theming hooks (override in your app to follow MudBlazor palette):
 *   --rxb-swipeout-bg      : row background          (default: var(--mud-palette-surface))
 *   --rxb-swipeout-radius  : row border radius       (default: 0)
 *   --rxb-action-min-width : minimum action width    (default: 64px)
 *   --rxb-overswipe-bg     : highlight when overswipe is armed
 */

.rxb-swipeout
{
    position: relative;
    overflow: hidden;
    background: var(--rxb-swipeout-bg, var(--mud-palette-surface, #fff));
    border-radius: var(--rxb-swipeout-radius, 0);
    /* JS owns every gesture inside a row — touchmove handlers call preventDefault on the first
       touchmove which is what actually wins the gesture from the browser's scroll heuristic.
       touch-action:none here is a fallback, in case preventDefault doesn't reach (rare). Page
       scrolling has to come from the surrounding scroll container; override --rxb-touch-action
       if you need row-internal scroll. */
    touch-action: var(--rxb-touch-action, none);
    user-select: none;
    -webkit-user-select: none;
}

.rxb-swipeout-content
{
    position: relative;
    z-index: 1;
    background: inherit;
    will-change: transform;
}

.rxb-swipeout-actions
{
    position: absolute;
    top: 0;
    bottom: 0;
    display: flex;
    align-items: stretch;
    z-index: 0;
    overflow: hidden;
    will-change: width;
    /* Width is owned by JS — JS sets a per-frame width (drag offset + animated armed bonus).
       Snap timing kicks in when the gesture ends (JS adds transition then). */
}

.rxb-swipeout-actions[data-swipeout-actions="left"]
{
    /* Below content — content slides right to reveal left actions, so left-aligned text moves
       with content and stays visible. */
    left: 0;
    z-index: 0;
    justify-content: flex-start;
}

.rxb-swipeout-actions[data-swipeout-actions="right"]
{
    /* Below content — content slides left to reveal right actions, mirroring the left panel
       behaviour. The whole row content moves with the gesture. */
    right: 0;
    z-index: 0;
    justify-content: flex-end;
}

.rxb-swipeout-actions > [data-swipeout-action]
{
    /* Length-driven flex-basis so the armed transition (basis 64 → 0) interpolates cleanly. */
    flex: 0 0 var(--rxb-action-min-width, 64px);
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    /* Spring curve for the non-trigger collapse on arm (basis 64 → 0). */
    transition: flex-basis 220ms cubic-bezier(0.34, 1.56, 0.64, 1),
                opacity 180ms ease;
}

/* Trigger always absorbs free panel space — as the panel grows past natural width with the
   gesture, the trigger button widens while the non-trigger stays at its natural basis. */
.rxb-swipeout-actions > [data-swipeout-action][data-swipeout-overswipe="true"]
{
    flex-grow: 1;
}

/* Opt-in iOS-style reveal: each button scales in from a small dot to its natural size as the
   panel reveals it. JS sets --rxb-reveal (0..1) per button based on how much of it is currently
   inside the visible panel area. transform-origin pins each button to the row edge it's emerging
   from so the scale anchors the button's edge to the panel edge while the rest unfolts inward.
   A surface-coloured border (with box-sizing: border-box, so flex-basis stays at 64) gives each
   button a "frame" of row-bg colour the scaling button grows into — matches the iOS Mail pill
   look. A small outer margin adds a constant gap between adjacent buttons that does not scale
   with the transform. align-self + fixed height keep buttons square inside tall rows; height is
   pinned (not aspect-ratio) so the trigger's width-only growth during overswipe arming widens
   the button without making it taller. */
.rxb-swipeout.rxb-reveal-scale .rxb-swipeout-actions > [data-swipeout-action]
{
    border: var(--rxb-reveal-border-width, 3px) solid var(--rxb-reveal-border-color, var(--rxb-swipeout-bg, var(--mud-palette-surface, #fff)));
    box-sizing: border-box;
    border-radius: var(--rxb-reveal-border-radius, 6px);
    margin: var(--rxb-reveal-gap, 1px);
    align-self: center;
    /* Adaptive height: row height minus a minimum top/bottom padding, capped at a maximum so
       very tall rows still produce a roughly square button. Width-only growth during overswipe
       arming is preserved because flex-grow only affects width. */
    height: calc(100% - 2 * var(--rxb-reveal-vpad, 4px));
    max-height: var(--rxb-action-max-size, var(--rxb-action-min-width, 64px));
}

/* The right action panel sits ON TOP of content (z-index: 2) so it slides in over the row text
   on left-swipe. With reveal-scale active there are gaps (margins + scaling) that would show the
   content text underneath. Filling the panel with the row's background colour hides the content
   through those gaps so only the colored action buttons remain visible. The left panel sits BELOW
   content and naturally shows the row's bg through any gaps, but we apply the same fill for visual
   consistency. */
.rxb-swipeout.rxb-reveal-scale .rxb-swipeout-actions
{
    background: var(--rxb-swipeout-bg, var(--mud-palette-surface, #fff));
}

.rxb-swipeout.rxb-reveal-scale .rxb-swipeout-actions[data-swipeout-actions="left"] > [data-swipeout-action]
{
    transform: scale(var(--rxb-reveal, 1));
    transform-origin: left center;
}

.rxb-swipeout.rxb-reveal-scale .rxb-swipeout-actions[data-swipeout-actions="right"] > [data-swipeout-action]
{
    transform: scale(var(--rxb-reveal, 1));
    transform-origin: right center;
}

/* The icon button inside the trigger gets an animated translateX + scale on arm. Animating the
   inner element (not the trigger span) keeps the colored panel bg flush to the row edge while
   the icon visibly shifts in the swipe direction — matches iOS Mail's delete behaviour, and is
   the *only* armed signal for single-button rows where the panel-widen bonus is suppressed. */
.rxb-swipeout-actions > [data-swipeout-action][data-swipeout-overswipe="true"] > *
{
    transform: translateX(0) scale(1);
    transition: transform 220ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

.rxb-swipeout-actions[data-swipeout-actions="left"].rxb-overswipe-armed > [data-swipeout-action][data-swipeout-overswipe="true"] > *
{
    transform: translateX(30px) scale(1.1);
}

.rxb-swipeout-actions[data-swipeout-actions="right"].rxb-overswipe-armed > [data-swipeout-action][data-swipeout-overswipe="true"] > *
{
    transform: translateX(-30px) scale(1.1);
}

/* Armed: the non-trigger collapses (multi-button case). The bonus-driven panel-widen + content
   slide handles the layout-level "auto-widen" signal for multi-button rows. */
.rxb-swipeout-actions.rxb-overswipe-armed > [data-swipeout-action]:not([data-swipeout-overswipe="true"])
{
    flex-basis: 0;
    opacity: 0;
}

/* Sortable */
.rxb-sortable
{
    position: relative;
    /* Empty lists still need a hit area for cross-list drops to land. */
    min-height: var(--rxb-sortable-empty-height, 56px);
    /* Reserved slot height for an incoming dragged item — set by JS via --rxb-drag-slot-height
       when this list is the active cross-list drop target. */
    padding-bottom: var(--rxb-drag-slot-height, 0);
    transition: padding-bottom 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94),
                background-color 150ms ease;
}

.rxb-sortable.rxb-sorting-active
{
    user-select: none;
    -webkit-user-select: none;
}

/* Cross-list drop target — subtle background tint follows MudBlazor's hover semantics. */
.rxb-sortable.rxb-drop-target
{
    background: var(--mud-palette-action-default-hover, rgba(0, 0, 0, 0.04));
}

/* Floating clone gets a soft error tint when the drop would remove the item from its source. */
.rxb-drag-ghost.rxb-drag-ghost-removing
{
    box-shadow: 0 0 0 2px var(--mud-palette-error, #f44336),
                var(--mud-elevation-12, 0 8px 24px rgba(0, 0, 0, 0.2));
}

/* While dragEl is collapsing into / out of its slot, the height transition is owned by JS;
   make sure the row clips its content so child padding doesn't leak. */
.rxb-sortable [data-rxb-sortable-item][style*="height"]
{
    overflow: hidden;
}

.rxb-sortable > [data-rxb-sortable-item]
{
    /* position:relative + a baseline z-index so the .rxb-sorting bump can lift the dragged row
       above its (transformed) siblings. Without position the z-index has no effect. */
    position: relative;
    z-index: 0;
    background: var(--rxb-swipeout-bg, var(--mud-palette-surface, #fff));
    will-change: transform;
}

/* Divider lives on the sortable wrapper, OUTSIDE the swipeout's clipped content,
   so it stays visible at full row width during a swipe. */
.rxb-sortable > [data-rxb-sortable-item]:not(:last-child)
{
    border-bottom: 1px solid var(--rxb-list-divider, var(--mud-palette-lines-default, rgba(0, 0, 0, 0.12)));
}

.rxb-sortable > [data-rxb-sortable-item].rxb-sorting
{
    z-index: 10;
    box-shadow: var(--mud-elevation-8, 0 4px 12px rgba(0,0,0,0.15));
    opacity: 0.96;
    transition: none !important;
}

[data-rxb-sort-handle]
{
    cursor: grab;
    touch-action: none;
}

.rxb-sortable.rxb-sorting-active [data-rxb-sort-handle]
{
    cursor: grabbing;
}

@media (prefers-reduced-motion: reduce)
{
    .rxb-swipeout-content,
    .rxb-swipeout-actions,
    .rxb-sortable [data-rxb-sortable-item]
    {
        transition: none !important;
    }
}
