@layer cinder.tokens, cinder.foundation, cinder.components, cinder.utilities;
@layer cinder.components {
  /* ========================================
 * SORTABLE LIST
 * ======================================== */

  .cinder-sortable-list {
    list-style: none;
    margin: 0;
    padding: 0;
  }

  .cinder-sortable-list__item {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    column-gap: var(--cinder-space-2);
    position: relative;
  }

  .cinder-sortable-list__item-content {
    min-inline-size: 0;
  }

  .cinder-sortable-list__item.cinder-sortable-item {
    cursor: default;
    user-select: none;
  }

  .cinder-sortable-item--lifted {
    transform: scale(1.02);
    box-shadow: var(--cinder-shadow-lg);
    z-index: 1;
    position: relative;
  }

  /*
   * During a pointer drag the source row becomes a placeholder — a translucent
   * ghost that marks the current drop target while the real preview follows the
   * pointer. The drop-target column / position is always visible because
   * visualColumns / visualItems already re-inserts the placeholder at the
   * destination index as the pointer moves.
   *
   * Outline is used instead of border so the drop indicator does not affect
   * the box model. Adding a border where none exists at rest would shift box
   * dimensions by 2px on each side, causing layout jitter and skewing the
   * midpoint geometry used by drop-target calculations.
   *
   * CIN-603: this box has no other visible content — its children are
   * `visibility: hidden` and its own background/box-shadow are already
   * suppressed below — so the element's own `opacity` only ever diluted this
   * outline. That made the drop indicator, the one thing this state exists to
   * convey, read at `border.muted` (a 1.4:1 decorative-hairline tier) further
   * cut to ~40% by element opacity: well under half of `border.muted`'s own
   * already-sub-3:1 weight. Moving to `border.control` (the 3:1 functional
   * tier) and dropping the element opacity — nothing else in this box needs
   * it — puts the indicator at its tier's full, undiluted alpha instead.
   */
  .cinder-sortable-item--placeholder {
    outline: 2px dashed var(--cinder-border);
    outline-offset: -1px;
    border-radius: var(--cinder-radius-md);
    box-shadow: none;
    background: transparent;
  }

  .cinder-sortable-item--placeholder > * {
    /* Hide child content from sight; placeholder conveys drop position only. */
    visibility: hidden;
  }

  /*
   * `.cinder-sortable-item--shifting` marks every row displaced by an active
   * drag (all rows except the lifted one, while a drag is in progress) — a
   * state hook for consumer overrides. It intentionally carries no transition
   * of its own here: neighboring rows are relocated by Svelte's keyed `#each`
   * physically moving DOM nodes on every reorder, which is an instant reflow,
   * not an animatable property change. Animating that motion requires a
   * FLIP-style effect (capture the pre-reorder rect, invert, then transition
   * back to identity) — a distinct feature with its own edge-case matrix
   * (keyboard moves, drop/cancel settling, cross-column KanbanBoard moves),
   * tracked separately rather than folded into this class.
   */

  @media (prefers-reduced-motion: reduce) {
    :root:not([data-cinder-reduced-motion='false']):not([data-reduced-motion='off'])
      .cinder-sortable-item--lifted {
      transform: none;
      box-shadow: var(--cinder-shadow-lg);
    }
  }

  .cinder-sortable-handle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--cinder-touch-target-min);
    min-height: var(--cinder-touch-target-min);
    background: none;
    border: none;
    padding: 0;
    cursor: grab;
    touch-action: none;
    color: inherit;
  }

  .cinder-sortable-handle:focus-visible {
    /* Focus-ring policy (docs/focus-ring-policy.md): a transparent outline (for
     * forced-colors / Windows High Contrast, replaced below) paired with the
     * shared box-shadow ring, rather than a colored outline. The normal-mode gap
     * is the shared `--cinder-ring-offset` baked into the box-shadow recipe — no
     * explicit `outline-offset` here, matching every other migrated component;
     * the old colored outline's hardcoded 2px offset is intentionally dropped.
     * The 2px outline-offset is only meaningful in the forced-colors block below,
     * where the real outline becomes visible. */
    outline: var(--cinder-ring-width) solid transparent;
    border-radius: 2px;
    box-shadow: var(--_cinder-focus-ring-shadow);
  }

  @media (forced-colors: active) {
    .cinder-sortable-handle:focus-visible {
      outline: var(--cinder-ring-width) solid ButtonText;
      outline-offset: 2px;
    }
  }

  .cinder-sortable-handle[aria-pressed='true'] {
    cursor: grabbing;
  }

  /* ========================================
   * DRAG PREVIEW OVERLAY
   * ======================================== */

  /*
   * The drag preview is a fixed-position portal appended to <body> during a
   * pointer drag. It clones the lifted item's content and follows the pointer
   * so the user always has a clear visual of what they are dragging.
   *
   * Positioning uses CSS custom properties set by _sortable-item.svelte:
   *   --preview-left / --preview-top   — row's bounding rect at lift time (physical viewport coords)
   *   --preview-dx / --preview-dy      — pointer delta since lift
   *   --preview-width / --preview-height — row dimensions at lift time
   *
   * Physical left/top (not logical inset-inline-start/inset-block-start) are used
   * because --preview-left/--preview-top come from getBoundingClientRect(), which
   * always returns physical viewport distances regardless of writing direction.
   * Using inset-inline-start would map to the right edge in RTL layouts, causing
   * the preview to appear on the wrong side of the viewport.
   */
  .cinder-sortable-drag-preview {
    position: fixed;
    top: calc(var(--preview-top, 0px) + var(--preview-dy, 0px));
    left: calc(var(--preview-left, 0px) + var(--preview-dx, 0px));
    width: var(--preview-width, auto);
    height: var(--preview-height, auto);
    z-index: var(--cinder-z-drag-preview);
    pointer-events: none;
    box-shadow: var(--cinder-shadow-md);
    border-radius: var(--cinder-radius-md);
    /* Subtle rotation and scale to distinguish preview from the placeholder. */
    transform: rotate(2deg) scale(1.02);
    transform-origin: center top;
    will-change: top, left;
    overflow: hidden;
  }

  /* Restore full opacity and visibility inside the preview clone. */
  .cinder-sortable-drag-preview > * {
    opacity: 1;
    visibility: visible;
  }

  /* Inside the preview clone keep children visible even if the source
     had placeholder--hidden children. */
  .cinder-sortable-drag-preview > * > * {
    visibility: visible;
  }

  @media (prefers-reduced-motion: reduce) {
    :root:not([data-cinder-reduced-motion='false']):not([data-reduced-motion='off'])
      .cinder-sortable-drag-preview {
      transform: none;
    }
  }
}
