/* ════════════════════════════════════════════════════════════════════════
   DS Modal primitive  (DS primitives phase — primitive 1 of 3)
   Controller: static/js/ds.js  ·  Macro: templates/_components.html ds_modal()
   Consumes tokens.css. Single active modal (v1; stacking deferred).
   ════════════════════════════════════════════════════════════════════════ */

.ds-modal-overlay {
  position: fixed; inset: 0;
  z-index: var(--z-modal);
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
  background: var(--cf-scrim);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  opacity: 0; visibility: hidden;
  transition: opacity var(--dur-slow) var(--ease), visibility var(--dur-slow) var(--ease);
}
.ds-modal-overlay.open { opacity: 1; visibility: visible; }

.ds-modal {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  width: 100%; max-width: 480px; max-height: 90vh;
  display: flex; flex-direction: column; overflow: hidden;
  transform: translateY(12px) scale(.99);
  transition: transform var(--dur-slow) var(--ease);
}
.ds-modal-overlay.open .ds-modal { transform: translateY(0) scale(1); }
/* Modal container receives focus on open for screen reader announcement (tabindex="-1"); not user-interactive, so outline suppressed. Interactive elements inside get their own :focus-visible ring via primitives. */
.ds-modal:focus { outline: none; }

/* ── Size variants ── */
.ds-modal--sm { max-width: 380px; }
.ds-modal--md { max-width: 480px; }
.ds-modal--lg { max-width: 640px; }
.ds-modal--xl { max-width: 820px; }

/* ── Header / title / close ── */
.ds-modal-header {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 16px 20px; border-bottom: 1px solid var(--border); flex-shrink: 0;
}
.ds-modal-title { font-size: var(--text-lg); font-weight: 700; color: var(--navy); }
.ds-modal-close {
  flex-shrink: 0;
  width: 44px; height: 44px;            /* 44×44 tap target */
  margin: -10px -10px -10px 0;          /* preserve visual alignment despite hit area */
  display: flex; align-items: center; justify-content: center;
  border: none; background: transparent; cursor: pointer;
  color: var(--muted); border-radius: var(--radius-md);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.ds-modal-close:hover { background: var(--gray-100); color: var(--navy); }
.ds-modal-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── Body / footer ── */
.ds-modal-body {
  padding: 20px; overflow-y: auto;
  font-size: var(--text-md); color: var(--text); line-height: 1.6;
}
.ds-modal-footer {
  display: flex; align-items: center; justify-content: flex-end; gap: 8px;
  padding: 14px 20px; border-top: 1px solid var(--border);
  flex-shrink: 0; flex-wrap: wrap;
}

/* ── Mobile: full-screen sheet ──
   A centered dialog cannot work on a phone: 90vh overstates the iOS visual
   viewport, the keyboard covers the lower half, and flex-centering clips both
   ends with no way to scroll to the X or the footer. At <=767px every ds-modal
   becomes a full-screen page (the support-chat page-mode pattern): the flex
   column is already in place, so the header stays pinned, the body is the only
   scroller, and the footer clears the home indicator. While the keyboard is up,
   ds.js (dsKbSync) pins the overlay to the visual viewport via inline
   top/height, which keeps the footer directly above the keyboard on iOS.
   ds-confirm opts back out to a compact centered dialog (ds-confirm.css).
   NOTE: this block must stay BELOW the base header/body/footer rules - the
   safe-area paddings here rely on later-in-file cascade order to win over the
   base padding shorthands (equal specificity). */
@media (max-width: 767px) {
  .ds-modal-overlay { padding: 0; align-items: stretch; }
  .ds-modal {
    max-width: 100% !important;
    width: 100%;
    height: 100%;
    max-height: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    transform: none;   /* no enter motion: inline keyboard pinning must not fight a transition */
    transition: none;
  }
  .ds-modal-header { padding-top: calc(16px + env(safe-area-inset-top)); }
  .ds-modal-body {
    flex: 1 1 auto;
    min-height: 0;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    /* footerless sheets: keep the last in-body action clear of the home indicator */
    padding-bottom: calc(20px + env(safe-area-inset-bottom));
  }
  .ds-modal-footer { padding-bottom: calc(14px + env(safe-area-inset-bottom)); }
  /* iOS zooms the page (breaking the visual-viewport pin) when a focused
     control is under 16px; --text-lg is 17px. !important: several modal
     textareas carry inline font-size:13px (feedback, lc-sms, copy-gen notes)
     and a zoomed page makes dsKbSync bail (vv.scale > 1). Mobile-only. */
  .ds-modal input:not([type="checkbox"]):not([type="radio"]),
  .ds-modal select,
  .ds-modal textarea { font-size: var(--text-lg) !important; }
}
