/**
 * App-level inbox extras: the conversation-row swipe and its visible menu, the
 * offline banner, the in-app notification banner, and the per-person
 * notification settings sheet.
 *
 * Owned by track T9 of the wa-inbox-pwa run. Created empty by T1 so the <link>
 * in index.html could be written once, before any other track opened that file.
 *
 * Linked AFTER /css/admin-whatsapp.css on purpose, so a rule here at equal
 * specificity wins on link order and needs no !important. It stays far above
 * /css/admin-person.css. The "admin" prefix is load-bearing: it is the only
 * thing scripts/bundle-css.mjs partitions on, and a differently named file
 * would ship the whole admin panel's CSS to every marketing visitor.
 *
 * Every colour here is a --wa-* token declared on `.admin-layout:has(.wai-page)`
 * in admin-whatsapp.css. None is a literal, because the dark set repoints all of
 * them and a literal would survive the switch and read as a bug in one theme
 * only. `--wa-on-accent` in particular FLIPS to near-black in dark, so it must
 * never be spelled #fff.
 */

/* ══ Swipe a conversation row (D30) ════════════════════════════════════════

   The wrapper exists because a <button> cannot contain a <button>: the kebab and
   the swipe affordance have to be SIBLINGS of `.wai-row`, not children of it.
   `overflow: hidden` clips the affordance until the row slides off it, and
   `touch-action: pan-y` hands the vertical axis back to the browser while
   reserving the horizontal one for us, which is what stops the scroller
   cancelling the gesture halfway through.

   NO SHEET MAY EVER BE RENDERED INSIDE `.wai-swipe`. `.wai-row` takes a
   transform, and a transformed ancestor becomes the containing block for a
   fixed-position AdminSheet, which would then open trapped inside one 72px row.
   The row menu is mounted once, from WaInboxOverlays.vue, for exactly this
   reason. */

.wai-swipe {
  position: relative;
  overflow: hidden;
  touch-action: pan-y;
}

.wai-swipe__actions {
  position: absolute;
  inset-block: 0;
  inset-inline: 0;
  display: flex;
  align-items: stretch;
  justify-content: space-between;
  pointer-events: none;
}

.wai-swipe__action {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  width: 96px;
  padding-inline: 14px;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--wa-on-accent, #ffffff);
  opacity: 0.55;
  transition: opacity 0.12s ease;
}

/* The LEADING action sits at the inline START, physically RIGHT in Hebrew, and
   is uncovered when the row slides toward the inline end. */
.wai-swipe__action--read {
  background: var(--wa-green);
}

/* The placeholder that keeps the trailing action pinned to the inline end on a
   row with nothing to mark as read. It paints nothing. */
.wai-swipe__action--void {
  background: none;
}

.wai-swipe__action--assign {
  justify-content: flex-end;
  background: var(--wa-ink-3);
}

/* Solid only once a release would actually commit. A panel that looks armed from
   the first pixel teaches the agent that any nudge fires the action. */
.wai-swipe--armed .wai-swipe__action {
  opacity: 1;
}

.wai-swipe .wai-row {
  transform: translateX(var(--wai-swipe-x, 0px));
  background: var(--wa-panel);
}

/* Only while springing back, so the row tracks the finger 1:1 during the drag. */
.wai-swipe--settling .wai-row {
  transition: transform 0.18s ease;
}

/* The divider moved out with the wrapper. `.wai-row:last-child::after` in
   admin-whatsapp.css can no longer match anything - with the wrapper in place no
   `.wai-row` is ever the last child of the scroller - so without this rule the
   final row grows a divider with nothing under it. That file belongs to another
   track for this run, so the dead rule is left standing and answered here. */
.wai-swipe:last-child .wai-row::after {
  content: none;
}

/* The wrapper clips, so the focus ring has to be drawn INSIDE the row. */
.wai-swipe .wai-row:focus-visible {
  outline: 2px solid var(--wa-green-ink);
  outline-offset: -2px;
}

/* The always-reachable door. On a fine pointer it appears on hover and focus,
   the way WhatsApp Web reveals its chevron; wherever there is no hover it is
   ALWAYS visible, because a swipe on its own fails discoverability and a
   hover-only control does not exist on a touch screen at all.

   INVISIBLE MUST ALSO MEAN UNTAPPABLE, AND THAT IS WHY `pointer-events` IS
   PAIRED WITH `opacity` IN EVERY RULE BELOW. `opacity: 0` hides paint and
   nothing else: the 36px button still hit-tests, so on a touch device with no
   hover it sat unseen over the row's inline end and swallowed the tap meant to
   open the conversation. The row simply did not respond, at random, wherever a
   thumb happened to land - the phone block used to be the only place the kebab
   was revealed, so an iPad, and a phone held in landscape, got the dead band
   and no way to see why.

   Any future rule that reveals this control must restore the hit area in the
   same declaration block, and any rule that hides it must take the hit area
   away. `tests/waRowKebabHitArea.spec.ts` reads this file and fails on a rule
   that does one without the other. */
.wai-swipe__menu {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: 4px;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: var(--radius-full, 980px);
  background: none;
  color: var(--wa-ink-3);
  font-size: 0.9rem;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
}

.wai-swipe:hover .wai-swipe__menu,
.wai-swipe:focus-within .wai-swipe__menu {
  opacity: 1;
  pointer-events: auto;
}

.wai-swipe__menu:focus-visible {
  opacity: 1;
  pointer-events: auto;
  outline: 2px solid var(--wa-green-ink);
  outline-offset: 2px;
}

/* Hover is the only thing that reveals the kebab above 767px, and a touch screen
   has none. A tablet and a phone in landscape are both wider than the phone
   block far below, so this is where they are answered: reveal the control, and
   pay the same 56px of row padding the phone block pays, or the unread pill and
   the delivery flag sit underneath it.

   A POINTER QUERY, NOT A WIDTH ONE. `(hover: none)` names the actual cause - a
   device that cannot reveal a hover-only control - and it deliberately adds no
   fourth width breakpoint: the two remain 1024px and 767px. `(pointer: coarse)`
   would be wrong here, since a coarse pointer that CAN hover reveals the kebab
   the ordinary way. */
@media (hover: none) {
  .wai-swipe__menu {
    opacity: 1;
    pointer-events: auto;
  }

  .wai-swipe .wai-row {
    padding-inline-end: 56px;
  }
}

/* ══ The row menu (D30) ════════════════════════════════════════════════════ */

.wai-rowmenu {
  display: flex;
  flex-direction: column;
}

.wai-rowmenu__item {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 52px;
  padding: 0 8px;
  border: 0;
  background: none;
  font-family: var(--font-body);
  font-size: 0.92rem;
  color: var(--wa-ink);
  text-align: start;
  text-decoration: none;
  cursor: pointer;
}

.wai-rowmenu__item:hover {
  background: var(--wa-hover);
}

.wai-rowmenu__item > i {
  flex: none;
  width: 20px;
  color: var(--wa-ink-3);
  text-align: center;
}

/* The app-level entry, separated from the four that act on this conversation. */
.wai-rowmenu__item--app {
  margin-block-start: 4px;
  border-block-start: 1px solid var(--wa-line);
  color: var(--wa-ink-2);
}

/* ══ The inbox snack (D30's undo, and every other transient notice) ════════

   Fixed rather than a grid row: it must not move the thread when it appears, and
   `.wai-page` has no transform, so a fixed child resolves against the viewport.
   z-index 1035 sits between the drawer (1030) and the sheet scrim (1040) on the
   ladder documented above `.adm-sheet-layer` in admin.css. Do NOT raise it: a
   notice that paints over an open sheet covers the controls being used. */

.wai-snack {
  position: fixed;
  inset-inline: 16px;
  inset-block-end: calc(76px + env(safe-area-inset-bottom));
  z-index: 1035;
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0;
  padding: 10px 14px;
  border-radius: var(--radius-md, 12px);
  background: var(--wa-ink);
  color: var(--wa-panel);
  font-size: 0.84rem;
  box-shadow: var(--wa-shadow-lg);
}

.wai-snack--error {
  background: var(--wa-danger-ink);
}

.wai-snack__text {
  flex: 1 1 auto;
  min-width: 0;
}

.wai-snack__action {
  flex: none;
  padding: 4px 10px;
  border: 0;
  border-radius: var(--radius-full, 980px);
  background: none;
  color: var(--wa-green);
  font-family: var(--font-body);
  font-size: 0.84rem;
  font-weight: 600;
  cursor: pointer;
}

.wai-snack__close {
  flex: none;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full, 980px);
  background: none;
  color: inherit;
  font-size: 0.8rem;
  opacity: 0.7;
  cursor: pointer;
}

.wai-snack__close:hover {
  opacity: 1;
}

/* ══ Offline, and the reconnect replay (D33) ══════════════════════════════

   `order: -1` is load-bearing. This banner is rendered by WaInboxOverlays.vue,
   which is the LAST child of `.wai-page`, and `.wai-page` is a flex column - so
   without it the line would appear under the grid instead of above it. `flex:
   none` keeps that column's height chain identical whether it is there or not.

   Deliberately NOT part of `.wai-page > .wai-strip`, which is hidden at 767px:
   the connection strip is hidden there because its content moved into the list's
   status dot, and this line has no other home. It must show on a phone, in both
   list and thread mode. */

.wai-offline,
.wai-pushprompt {
  order: -1;
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 40px;
  margin: 0;
  padding: 0.3rem var(--space-md, 16px);
  font-size: 0.82rem;
  color: var(--wa-ink);
}

.wai-offline {
  background: linear-gradient(var(--wa-warn-wash), var(--wa-warn-wash)), var(--wa-header);
  border-block-end: 1px solid var(--wa-warn-line);
}

.wai-offline > i {
  flex: none;
  font-size: 0.8rem;
  color: var(--wa-warn);
}

.wai-offline--replaying > i {
  color: var(--wa-green-ink);
}

.wai-offline__text,
.wai-pushprompt__text {
  flex: 1 1 auto;
  min-width: 0;
}

/* ══ The push prompt strip (D35's in-app enable button) ════════════════════ */

.wai-pushprompt {
  background: linear-gradient(var(--wa-green-wash-2), var(--wa-green-wash-2)), var(--wa-header);
  border-block-end: 1px solid var(--wa-green-line);
}

.wai-pushprompt > i {
  flex: none;
  font-size: 0.8rem;
  color: var(--wa-green-ink);
}

.wai-pushprompt__action {
  flex: none;
  padding: 4px 10px;
  border: 0;
  border-radius: var(--radius-full, 980px);
  background: var(--wa-green);
  color: var(--wa-on-accent, #ffffff);
  font-family: var(--font-body);
  font-size: 0.78rem;
  font-weight: 600;
  cursor: pointer;
}

.wai-pushprompt__action--quiet {
  background: none;
  color: var(--wa-green-ink);
  text-decoration: underline;
}

.wai-pushprompt__close {
  flex: none;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full, 980px);
  background: none;
  color: var(--wa-ink-3);
  font-size: 0.8rem;
  cursor: pointer;
}

/* ══ The in-app arrival banner (D26 in-app half, D28) ══════════════════════

   Fixed at the top of the viewport, on the same rung as the snack: above the
   drawer at 1030, below the sheet scrim at 1040. At most one is on screen; a
   second arrival replaces it and a third does not queue, which waAlerts.ts
   enforces - a stack of banners over a conversation is a worse version of the
   list already on screen. */

.wai-alert {
  position: fixed;
  inset-block-start: calc(8px + env(safe-area-inset-top));
  inset-inline: 12px;
  z-index: 1035;
  display: flex;
  align-items: stretch;
  gap: 4px;
  padding: 2px;
  border: 1px solid var(--wa-line);
  border-radius: var(--radius-md, 12px);
  background: var(--wa-panel);
  box-shadow: var(--wa-shadow-lg);
}

.wai-alert__body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--radius-sm, 8px);
  background: none;
  font-family: var(--font-body);
  text-align: start;
  cursor: pointer;
}

.wai-alert__body:hover {
  background: var(--wa-hover);
}

.wai-alert__title {
  overflow: hidden;
  font-size: 0.86rem;
  font-weight: 600;
  color: var(--wa-ink);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wai-alert__preview {
  overflow: hidden;
  font-size: 0.8rem;
  color: var(--wa-ink-2);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wai-alert__close {
  flex: none;
  width: 36px;
  border: 0;
  border-radius: var(--radius-sm, 8px);
  background: none;
  color: var(--wa-ink-3);
  font-size: 0.9rem;
  cursor: pointer;
}

.wai-alert__close:hover {
  background: var(--wa-hover);
}

/* ══ The notification settings screen (D34) ════════════════════════════════ */

.wapn {
  display: flex;
  flex-direction: column;
}

.wapn__notice {
  margin: 0 0 8px;
  padding: 8px 10px;
  border-radius: var(--radius-sm, 8px);
  background: var(--wa-sunken-soft);
  font-size: 0.82rem;
  color: var(--wa-ink-2);
}

.wapn__notice--warn {
  background: linear-gradient(var(--wa-warn-wash), var(--wa-warn-wash)), var(--wa-panel);
  color: var(--wa-warn);
}

.wapn__install {
  align-self: flex-start;
  margin-block-end: 8px;
}

.wapn__row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 52px;
  padding: 8px 0;
  border-block-start: 1px solid var(--wa-line);
}

.wapn__row:first-of-type {
  border-block-start: 0;
}

/* Indented under the switch it belongs to. `padding-inline-start`, never a left
   padding: this island is RTL and a physical property points the wrong way. */
.wapn__row--sub {
  padding-inline-start: 22px;
}

.wapn__row--device {
  align-items: flex-start;
}

/* The one DISPLAY setting on a screen otherwise about notifications (D10): the
   dark skin. A heavier rule than the rows above it marks the group change, so
   the switch does not read as another notification preference. A token, never a
   literal - the dark set repoints this line to a light alpha. */
.wapn__row--theme {
  border-block-start: 1px solid var(--wa-line-strong);
}

.wapn__label {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.wapn__title {
  font-size: 0.92rem;
  color: var(--wa-ink);
}

.wapn__hint {
  font-size: 0.78rem;
  color: var(--wa-ink-2);
}

.wapn__error {
  margin: 0;
  font-size: 0.78rem;
  color: var(--wa-danger-ink);
}

.wapn__device-btn {
  flex: none;
  align-self: center;
}

/* The native switch, tinted to the panel's one accent. `accent-color` is the
   whole control: no pseudo-element scaffolding, no hidden input, and it keeps
   the platform's own focus ring and its 44px tap target on a phone. */
.wapn__switch {
  flex: none;
  width: 44px;
  height: 26px;
  margin: 0;
  accent-color: var(--wa-green);
  cursor: pointer;
}

.wapn__times {
  gap: 16px;
}

.wapn__time-field {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.wapn__time-label {
  font-size: 0.82rem;
  color: var(--wa-ink-2);
}

/* `direction: ltr` on the field itself. The control's own text is HH:MM, and the
   RTL island would otherwise reorder the colon and the two pairs of digits into
   something that reads as a data bug. */
.wapn__time {
  direction: ltr;
  padding: 6px 8px;
  border: 1px solid var(--wa-line-strong);
  border-radius: var(--radius-sm, 8px);
  background: var(--wa-raised);
  font-family: var(--font-body);
  font-size: 0.86rem;
  color: var(--wa-ink);
}

.wapn__note {
  margin: 8px 0 0;
  font-size: 0.75rem;
  line-height: 1.5;
  color: var(--wa-ink-3);
}

/* ══ Phones ═══════════════════════════════════════════════════════════════ */

@media (max-width: 767px) {
  /* The kebab is permanent here, and the row pays for it: without the extra
     inline-end padding the unread pill and the delivery flag sit under the 36px
     button. 16px of row padding + 36px of button + 4px of offset.

     The `(hover: none)` block near the top of this file already covers every
     real phone. This one is what is left over: a desktop window dragged below
     768px, which hovers and so would otherwise get the narrow layout with a
     hover-only kebab. `pointer-events` travels with `opacity` here for the same
     reason it does everywhere else - visible and untappable is the same defect
     the other way round. */
  .wai-swipe__menu {
    opacity: 1;
    pointer-events: auto;
  }

  .wai-swipe .wai-row {
    padding-inline-end: 56px;
  }
}

@media (min-width: 1025px) {
  .wai-snack {
    inset-inline-start: auto;
    inset-inline-end: 24px;
    inset-block-end: 24px;
    max-width: 380px;
  }

  .wai-alert {
    inset-inline-start: auto;
    inset-inline-end: 24px;
    max-width: 380px;
  }
}

/* ══ Reduced motion ═══════════════════════════════════════════════════════

   The spring-back and the affordance fade are both decoration. The drag itself
   is not animated - it tracks the finger - so nothing here removes feedback. */

@media (prefers-reduced-motion: reduce) {
  .wai-swipe__action,
  .wai-swipe--settling .wai-row {
    transition: none;
  }
}

/* ══ The notification bell (D34) ══════════════════════════════════════════

   The entry point to the per-person notification settings, in the list
   header's search row.

   It CANNOT borrow `.wai-list__new`, the only existing control with the right
   shape, because admin-whatsapp.css hides that class outright at 1024px and
   below: D15 dropped new-chat on phones, since the API cannot cold-start a
   conversation with someone who has not written first. Inheriting that rule
   would hide the bell on exactly the devices D34 exists for, which is every
   device that can receive a push. So the shape is restated here rather than
   shared, and this file is linked AFTER admin-whatsapp.css.

   Written by the orchestrator at T14's request: the bell's markup is T14's,
   every other D34 control in this file is T9's, and no stylesheet was on
   either track's owned-file list. One writer, after both tracks went idle. */

.wai-list__notify {
  position: relative;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: 1px solid var(--wa-line);
  border-radius: var(--radius-full, 980px);
  background: transparent;
  color: var(--wa-ink-2);
  font-size: 0.85rem;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease, background-color 0.15s ease;
}

/* 38px of paint, 44px of target. Same idiom as `.wai-list__new`: the halo is a
   transparent ::after that overhangs by 3px on every side, so the control keeps
   its visual size while a thumb gets the full recommended tap area. */
.wai-list__notify::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: -3px;
}

.wai-list__notify:hover {
  background: var(--wa-sunken);
  color: var(--wa-ink);
  border-color: var(--wa-line-strong);
}

.wai-list__notify:focus-visible {
  outline: 2px solid var(--wa-green-ink);
  outline-offset: 2px;
}

/* Notifications are off on this device. The bell is the only place that fact is
   visible without opening the sheet, and a bell that looks identical whether or
   not it will ever ring is the affordance failing at its one job. Deliberately
   a muted ink rather than a warning colour: it is a setting, not a fault. */
.wai-list__notify--off {
  color: var(--wa-ink-3);
}

.wai-list__notify--off::before {
  content: '';
  position: absolute;
  inset-block-start: 5px;
  inset-inline-end: 5px;
  width: 7px;
  height: 7px;
  border: 2px solid var(--wa-panel);
  border-radius: var(--radius-full, 980px);
  background: var(--wa-ink-3);
}

@media (prefers-reduced-motion: reduce) {
  .wai-list__notify {
    transition: none;
  }
}
