/* ═══════════════════════════════════════════════════════════════════════
   Column picker (.acp) - src/components/admin/AdminColumnPicker.vue
   plus the drag affordance it puts on a real <th> (.acp-th, at the end).

   Hosted by three list screens (leads, the open-day roster, enrollments).
   The trigger lives at the inline-end of each page's .reg-filter-bar and NOT
   in the table header, because all three tables sit inside overflow-x:auto
   wrappers where a <th>-anchored popover is clipped at any z-index, and
   nothing in this panel teleports (the --adm-* tokens are declared on
   .admin-layout, not :root - see AdminSheet.vue).

   Geometry is deliberately borrowed, not invented:
     - the trigger from .adm-ms__trigger (admin.css:7973), so it sits on the
       same baseline as the AdminMultiSelect filters it shares a row with;
     - the count pill from .adm-ms__count (admin.css:8163) byte for byte, and
       NOT from the blue .adm-ms__badge: in this bar blue means "a filter is
       narrowing which rows exist", and hiding a column narrows nothing;
     - the layer / scrim / panel ladder from .adm-ms (60 for the desktop
       popover, 1040 for the phone sheet - AdminSheet's rung);
     - .drag-handle and .drag-reorder-move from the shared drag kit
       (admin.css:1634-1678) verbatim, because those two are unscoped.
       .drag-active and .drop-above/.drop-below are NOT reusable - they are
       scoped to .tree-header / tr - so their looks are restated below at
       identical values so the family resemblance holds.

   TWO SURFACES, ONE OPERATION. The picker list and the table's own movable
   <th>s both write through useAdminColumns' move()/drop(). The keyboard twin
   for BOTH is the picker's .acp__move-btn pair plus Alt+Arrow. Do not add a
   keyboard handler to the header: a <th> cannot host the twin (the roster's
   headers are not even focusable, by decision), and a second implementation
   of one operation is how the two surfaces start disagreeing.

   ORDER is a >=1025px feature: below that all three tables drop <thead>
   entirely (admin.css:5023 .reg-table thead, admin-enrollments.css .enr-table
   thead) and the rows are reflowed into cards by explicit `order:` ladders and
   grid-template-areas, so the DOM sequence is ignored. HIDING is live at every
   width, because a hidden column has no <td> at all. The component says so in
   one line of copy; this sheet says so by dimming the reorder controls in the
   card band.

   PHYSICAL VALUES, exactly two, both annotated where they sit:
   .acp__row--drop-before / --drop-after. Everything else is logical.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Trigger ─────────────────────────────────────────────────────────── */

.acp {
  position: relative;
  /* Pins the control to the inline-end edge of .reg-filter-bar on whatever
     wrapped line it lands on, so it does not jump sideways when the
     conditional "ניקוי סינון" button appears and disappears beside it. */
  margin-inline-start: auto;
}

.acp__trigger {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  /* The measured height of the .form-select and the AdminMultiSelect triggers
     on this row: a button's line box is shorter than a select's, so without
     the floor this control sits 5px low on that baseline. */
  min-height: 2.45rem;
  padding: 0.45rem 0.7rem;
  background: #fff;
  border: 1px solid #ddd;
  border-radius: 6px;
  font-family: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--adm-ink-2);
  cursor: pointer;
  transition: border-color 0.2s;
}

.acp__trigger:hover:not(:disabled) {
  border-color: rgba(0, 113, 227, 0.35);
  color: var(--adm-ink);
}

.acp__trigger:focus-visible,
.acp__trigger--open {
  outline: none;
  border-color: var(--adm-accent);
  box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.12);
}

.acp__trigger:disabled {
  background: #f6f7f9;
  color: var(--adm-ink-3);
  cursor: not-allowed;
}

.acp__trigger-icon {
  font-size: 0.9rem;
  color: var(--adm-ink-3);
}

.acp__trigger:hover:not(:disabled) .acp__trigger-icon,
.acp__trigger--open .acp__trigger-icon {
  color: var(--adm-accent);
}

.acp__trigger-text {
  white-space: nowrap;
}

/* GREY, not the blue .adm-ms__badge. Same fill, ink, size and numeric variant
   as .adm-ms__count (admin.css:8163) so it reads as a COUNT and not as a
   filter state. */
.acp__count {
  flex: 0 0 auto;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  background: #eef2f7;
  color: #5b6470;
  font-size: 0.7rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Order customised, nothing hidden: there is no number to print, and a trigger
   that looked factory-default would hide the fact that it is not. */
.acp__dot {
  flex: 0 0 auto;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--adm-accent);
}

/* ── The announcement channel ────────────────────────────────────────────
   role="status" aria-live="polite", mounted for the life of the page. After a
   keyboard move Vue moves the SAME keyed checkbox, so focus never leaves it
   and no screen reader re-announces the aria-label whose position just
   changed. Without this the keyboard twin performs a move and says nothing.
   Repo-wide there is no .sr-only / .visually-hidden utility, so the clip is
   declared here, and .acp__why shares it.

   .acp__why is the lock REASON as text the accessibility tree can reach: the
   locked row's checkbox points at it with aria-describedby, so a keyboard or
   screen-reader user hears why the row cannot move or hide. The visible half of
   that same fact is the "קבוע" tag and the pointer half is the title; a title
   alone is invisible to both of those readers. It is absolutely positioned, so
   a full sentence sitting inside a one-line flex row adds no flex item and
   moves nothing. */
.acp__live,
.acp__why {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ── Layer / panel ───────────────────────────────────────────────────── */

.acp__scrim {
  display: none;
}

.acp__panel {
  position: absolute;
  inset-block-start: calc(100% + 6px);
  /* END, not start. The trigger sits at the inline-end of the filter bar, so a
     start-anchored 360px panel would open past the viewport edge. Anchored
     here it aligns its end edge with the trigger's and grows back into the
     page. */
  inset-inline-end: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  width: max-content;
  min-width: min(100%, 320px);
  max-width: min(360px, 92vw);
  background: rgba(255, 255, 255, 0.97);
  -webkit-backdrop-filter: blur(24px) saturate(1.5);
  backdrop-filter: blur(24px) saturate(1.5);
  border: 1px solid var(--adm-glass-border);
  border-radius: 12px;
  box-shadow: 0 20px 56px rgba(0, 60, 130, 0.18);
}

.acp__head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.55rem 0.7rem 0.3rem;
}

.acp__head-title {
  flex: 1;
  min-width: 0;
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--adm-ink-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.acp__reset {
  flex: 0 0 auto;
  padding: 0.12rem 0.35rem;
  border: none;
  background: none;
  border-radius: 6px;
  font-family: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--adm-accent-ink);
  cursor: pointer;
}

.acp__reset:hover {
  background: rgba(0, 113, 227, 0.08);
}

.acp__reset:focus-visible {
  outline: 2px solid var(--adm-accent);
  outline-offset: 1px;
}

.acp__close {
  display: none;
}

.acp__hint {
  margin: 0;
  padding: 0 0.75rem 0.5rem;
  font-size: 0.74rem;
  line-height: 1.5;
  color: var(--adm-ink-3);
}

/* ── The list ────────────────────────────────────────────────────────── */

.acp__list {
  display: flex;
  flex-direction: column;
  gap: 1px;
  max-height: 21rem;
  padding: 0 0.4rem 0.4rem;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Fences the movable zone off from the locked head and the locked tail. NOT a
   group heading: the list IS the table's order, and a heading over a set the
   reader is about to reorder would stop being true on the first drag. */
.acp__fence {
  height: 0;
  margin: 0.3rem 0.5rem;
  border: none;
  border-block-start: 1px solid var(--adm-line);
}

/* ── One row ─────────────────────────────────────────────────────────── */

.acp__row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 34px;
  padding: 0.25rem 0.4rem;
  border-radius: 8px;
  font-size: 0.84rem;
  color: var(--adm-ink);
  background: none;
}

.acp__row:hover {
  background: rgba(0, 113, 227, 0.05);
}

/* The roving tab stop is the checkbox, so the ring has to read as the ROW's.
   Inset, because an outer ring on the first or last row is clipped by the
   list's own overflow. */
.acp__row:focus-within {
  background: rgba(0, 113, 227, 0.09);
  box-shadow: inset 0 0 0 1px rgba(0, 113, 227, 0.45);
}

.acp__row--hidden .acp__name {
  color: var(--adm-ink-3);
}

.acp__grip {
  flex: 0 0 auto;
  font-size: 0.8rem;
  color: #c2c8d2;
}

/* .drag-handle (admin.css:1634) already supplies width, cursor:grab, the hover
   colour and user-select:none; this only tunes the resting tint so a 22-row
   list does not shout. */
.acp__row:hover .acp__grip.drag-handle {
  color: var(--adm-ink-3);
}

.acp__grip--locked {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  font-size: 0.72rem;
  color: #c2c8d2;
  cursor: default;
}

.acp__box {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  margin: 0;
  accent-color: var(--adm-accent);
  cursor: pointer;
}

/* aria-disabled, never the disabled ATTRIBUTE: a disabled input drops out of
   the roving tabindex, so a keyboard reader would never reach a locked row or
   hear why it is locked. The click is cancelled in script instead. */
.acp__box[aria-disabled='true'] {
  opacity: 0.5;
  cursor: not-allowed;
}

.acp__name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}

.acp__row--locked .acp__name {
  color: var(--adm-ink-2);
  cursor: default;
}

/* The VISIBLE half of "this column cannot move or hide". A title attribute
   alone is invisible on touch and to a keyboard user. */
.acp__tag {
  flex: 0 0 auto;
  padding: 0.05rem 0.35rem;
  border-radius: 999px;
  background: #eef2f7;
  color: var(--adm-ink-3);
  font-size: 0.64rem;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.acp__move {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 1px;
}

.acp__move-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: none;
  background: none;
  border-radius: 6px;
  color: var(--adm-ink-3);
  font-size: 0.72rem;
  cursor: pointer;
}

.acp__move-btn:hover:not(:disabled) {
  background: rgba(0, 113, 227, 0.1);
  color: var(--adm-accent-ink);
}

.acp__move-btn:focus-visible {
  outline: 2px solid var(--adm-accent);
  outline-offset: -2px;
}

.acp__move-btn:disabled {
  opacity: 0.32;
  cursor: default;
}

/* ── Drag states, VERTICAL list ──────────────────────────────────────────
   Restated rather than borrowed: .tree-header.drag-active / tr.drag-active and
   .tree-header.drop-above / .drop-below (admin.css:1655-1678) are scoped to
   .tree-header and tr, so none of them can reach a <div>. Values are identical
   on purpose, and var(--adm-accent) resolves to the #0071E3 those rules use.

   PHYSICAL VALUES, and they are correct HERE: box-shadow has no logical form
   in any shipping engine, but these offsets are on the BLOCK axis of a
   vertical list, and the block axis does not flip under direction:rtl. The
   inline-axis equivalent for the table header at the end of this file must NOT
   be drawn this way - see the note there. */
.acp__row--dragging {
  opacity: 0.6;
  background: rgba(0, 113, 227, 0.08);
  box-shadow: 0 0 0 1px rgba(0, 113, 227, 0.3);
}

.acp__row--drop-before {
  box-shadow: 0 -2px 0 0 var(--adm-accent);
}

.acp__row--drop-after {
  box-shadow: 0 2px 0 0 var(--adm-accent);
}

/* ── Foot ────────────────────────────────────────────────────────────── */

.acp__note,
.acp__keys {
  margin: 0;
  padding: 0.4rem 0.75rem 0;
  font-size: 0.72rem;
  line-height: 1.5;
  color: var(--adm-ink-3);
}

.acp__note {
  margin-block-start: 0.35rem;
  padding-block-start: 0.5rem;
  border-block-start: 1px solid var(--adm-line);
}

.acp__keys {
  padding-block-end: 0.6rem;
}

.acp__foot {
  display: none;
}

/* ── Transition (matches .adm-ms) ────────────────────────────────────── */

.acp-enter-active,
.acp-leave-active {
  transition: opacity 0.14s ease;
}

.acp-enter-from,
.acp-leave-to {
  opacity: 0;
}

/* ═══ Card band (<=1024px): hiding stays live, ORDER does not ══════════
   Below 1025px every one of the three tables is reflowed into cards by
   explicit `order` ladders and grid-template-areas, so the DOM sequence a
   reorder writes is ignored, and <thead> is not rendered at all. The reorder
   controls go visibly inert rather than silently ineffective; the component
   swaps its hint line to say so in words. */
@media (max-width: 1024px) {
  .acp__panel {
    /* Near-opaque stand-in for glass on phone/tablet chrome (shell decision
       F5): blur composited over a scrolling layer is the classic WebKit
       repaint flicker. */
    background: var(--adm-surface-solid, rgba(255, 255, 255, 0.97));
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  .acp__grip,
  .acp__move {
    opacity: 0.3;
  }

  .acp__keys {
    display: none;
  }
}

/* ═══ Phone (<=767px): the panel docks as a sheet ══════════════════════ */
@media (max-width: 767px) {
  .acp {
    position: static;
  }

  /* 44px touch floor on the trigger too: 2.45rem is 39px, which is under it. */
  .acp__trigger {
    min-height: 44px;
  }

  .acp__layer {
    position: fixed;
    inset: 0;
    z-index: 1040;
  }

  .acp__scrim {
    display: block;
    position: absolute;
    inset: 0;
    background: rgba(25, 26, 35, 0.32);
  }

  .acp__panel {
    position: absolute;
    inset-block-start: auto;
    inset-block-end: 0;
    inset-inline: 0;
    width: 100%;
    min-width: 0;
    max-width: none;
    max-height: 88dvh;
    border-radius: 20px 20px 0 0;
    border-block-end: none;
    box-shadow: 0 -12px 40px rgba(0, 60, 130, 0.16);
  }

  .acp__head {
    position: relative;
    padding: 1.1rem 1.1rem 0.5rem;
  }

  .acp__head-title {
    font-size: 1rem;
    font-weight: 700;
    color: var(--adm-ink);
    text-transform: none;
    letter-spacing: 0;
  }

  .acp__reset {
    min-height: 44px;
    padding: 0.3rem 0.6rem;
    font-size: 0.86rem;
  }

  .acp__close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    margin-inline-end: -10px;
    border: none;
    background: none;
    border-radius: 12px;
    color: var(--adm-ink-3);
    font-size: 1.05rem;
    cursor: pointer;
  }

  .acp__hint,
  .acp__note {
    padding-inline: 1.1rem;
    font-size: 0.8rem;
  }

  .acp__list {
    max-height: none;
    padding: 0 0.7rem 0.4rem;
  }

  .acp__row {
    min-height: 46px;
    padding: 0.4rem 0.5rem;
    font-size: 0.95rem;
  }

  .acp__box {
    width: 22px;
    height: 22px;
  }

  .acp__move-btn {
    width: 44px;
    height: 44px;
    font-size: 0.85rem;
  }

  .acp__foot {
    display: block;
    padding: 0.6rem 1.1rem calc(0.9rem + env(safe-area-inset-bottom));
    border-block-start: 1px solid var(--adm-line);
  }

  .acp__done {
    width: 100%;
    min-height: 44px;
    border: none;
    border-radius: 12px;
    background: var(--adm-accent);
    color: #fff;
    font-family: inherit;
    font-size: 0.95rem;
    font-weight: 600;
    cursor: pointer;
  }
}

/* ═══ The drag affordance ON a real <th> ═══════════════════════════════
   Owner decision 11: the movable headers are directly draggable. The three
   locked columns (selection, row name, row actions) render outside the
   registry loop and never receive any of this.

   The classes are applied by useAdminColumnHeaderDrag().thClass(), so nothing
   in admin.css is edited - several CSS-text specs parse that file rule by
   rule.

   Verified safe from this stylesheet's position in index.html: no rule in
   admin.css, admin-leads.css, admin-enrollments.css or admin-open-day.css
   declares `position` on a MOVABLE <th>. The only <th> position declarations
   anywhere in the three tables are admin-enrollments.css:507 and :518, scoped
   by class to th.enr-th-check and th.enr-th-name, both locked. */
.acp-th {
  position: relative;
}

/* Decoration ONLY. Not a drag source, not focusable, not in the accessibility
   tree: pointer-events:none is what keeps the <th> itself the single drag
   source, so a press on the glyph starts the same gesture as a press anywhere
   else on the header. */
.acp-th__grip {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: 2px;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 20px;
  color: #c2c8d2;
  font-size: 0.7rem;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.12s ease;
}

.acp-th:hover .acp-th__grip,
.acp-th:focus-within .acp-th__grip,
.acp-dragging .acp-th__grip {
  opacity: 1;
}

.acp-th[draggable='true'] {
  cursor: grab;
}

.acp-th--dragging {
  opacity: 0.55;
  cursor: grabbing;
}

/* The drop line is on the INLINE axis, so it is a pseudo-element on LOGICAL
   insets and NOT the vertical list's box-shadow trick above: a
   `box-shadow: 2px 0 0 0` means the physical RIGHT edge and would point at the
   wrong neighbour the moment a header renders outside one of the RTL islands
   (.admin-main is direction:ltr, admin.css:419, and each page re-establishes
   RTL on its own root - .reg-page/.leads-page at admin.css:7110, .enr-page at
   admin-enrollments.css:9).

   In RTL "before" resolves to the RIGHT edge, which is where a Hebrew reader
   expects "earlier" to be, so the logical inset needs no copy to explain it.
   The class names an EDGE and the drag state names a SEQUENCE position; the
   mapping lives in one line of thClass(). Absolutely positioned, so it affects
   no layout - the same property box-shadow was chosen for in the list. */
.acp-th--drop-start::after,
.acp-th--drop-end::after {
  content: '';
  position: absolute;
  inset-block: 0;
  width: 2px;
  background: var(--adm-accent);
  pointer-events: none;
}

.acp-th--drop-start::after {
  inset-inline-start: 0;
}

.acp-th--drop-end::after {
  inset-inline-end: 0;
}

/* The sort hover wash (admin.css:3654) would otherwise keep firing under a
   column that is being dragged, which reads as "this will sort". Specificity
   (0,3,0) beats it outright, so the cascade order cannot decide this. */
.acp-dragging .reg-th-sort:hover {
  background: transparent;
  color: #666;
}

/* ═══ Reduced motion ══════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  .acp-enter-active,
  .acp-leave-active,
  .acp__trigger,
  .acp-th__grip,
  .drag-reorder-move {
    transition: none;
  }
}
