/* ==========================================================================
   ui-modal for the team bios (2026-09-13), lifted from AG INTERACTIVE-
   COMPONENTS.md section 12 and re-keyed to Arbor's tokens: z-index 40 (the
   AG z map), 0.3s, backdrop blur, header with a ROUND close at the top right
   that never sits over the words (the header is its own bar), body scrolls.
   The body is the live bio page's content: photo, eyebrow, name, paragraphs,
   credentials line. Tokens only.
   ========================================================================== */
/* the checkpoint's bare reset rules every div; nothing in a modal is a section */
.ui-modal div, .ui-modal p, .ui-modal figure { border-top: 0; margin-block: 0; padding-top: 0; }
/* 2026-09-13, Quinten: "the background turns white". The first build put
   backdrop-filter on the backdrop and faded the modal ROOT's opacity; in
   Chrome on Windows a backdrop-filter under an ancestor whose opacity
   animates can paint the backdrop root white for the length of the fade.
   Now: the root never animates (hidden/shown by visibility only), the veil
   is a solid navy at 78%, and the BLUR is a plain CSS filter on <main>
   while a modal is open (body.has-modal, set by ui-modal.js). Only the
   container fades, by its own opacity, and it never transforms. */
.ui-modal {
  position: fixed; inset: 0; z-index: 40; margin: 0; border: 0;   /* the modal is itself a div under the bare reset */
  display: flex; align-items: center; justify-content: center;
  padding: 21px;
  visibility: hidden;
  font-family: var(--font-body);
}
.ui-modal:not([hidden]) { visibility: visible; }
.ui-modal[hidden] { display: flex; }   /* keep the box; visibility does the hiding */
.ui-modal-backdrop {
  position: absolute; inset: 0;
  background: rgba(9, 20, 34, 0.78);   /* navy-deep at 78%, plain rgba on purpose */
}
body.has-modal > main { filter: blur(9px); }
body.has-modal > main, body.has-modal > main * { pointer-events: none; }
.ui-modal-container {
  position: relative;
  background: var(--paper); color: var(--arbor-text);
  border-radius: 14px;
  box-shadow: 0 21px 63px color-mix(in srgb, var(--lp-navy-deep) 60%, transparent);
  max-width: 820px; width: min(100%, 820px);
  max-height: calc(100dvh - 42px);
  display: grid; grid-template-rows: auto minmax(0, 1fr);
  overflow: hidden;
  /* the container fades by its own opacity, and never transforms: a layer
     rasterised mid-transform can stay soft, which read as "pixelated" */
  opacity: 0;
  transition: opacity 0.3s ease-out;
}
.ui-modal:not([hidden]) .ui-modal-container { opacity: 1; }

/* the header bar: navy, the page's own "Meet X" line, the round close */
.ui-modal .ui-modal-header {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 14px 14px 14px 28px;
  background: var(--lp-navy); color: var(--c-white);
  border-bottom: 1px solid color-mix(in srgb, var(--lp-gold) 42%, transparent);
}
.ui-modal-title {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1.25rem, 1.1rem + 0.7vw, 1.75rem); line-height: 1.1; letter-spacing: -0.01em;
  margin: 0; color: var(--c-white);
}
.ui-modal-close {
  flex: 0 0 auto; width: 49px; height: 49px;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--c-white) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--c-white) 28%, transparent);
  border-radius: 50%;
  color: var(--c-white); cursor: pointer;
  padding: 0; line-height: 0;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: background 0.3s ease-out, border-color 0.3s ease-out, transform 0.3s ease-out;
}
@media (hover: hover) {
  .ui-modal-close:hover { background: var(--lp-gold); border-color: var(--lp-gold); color: var(--lp-navy); }
}
.ui-modal-close:focus-visible { outline: 3px solid var(--lp-gold); outline-offset: 3px; }
.ui-modal-close:active { transform: scale(0.94); }
.ui-modal-close svg { display: block; }

/* the body: the bio page, photo beside the words */
.ui-modal .ui-modal-body {
  overflow-y: auto; overscroll-behavior: contain;
  padding: clamp(21px, 2vw + 7px, 35px) clamp(21px, 2vw + 7px, 35px) clamp(28px, 2vw + 14px, 42px);
  display: grid; grid-template-columns: minmax(0, 240px) minmax(0, 1fr);
  gap: clamp(21px, 2vw + 7px, 35px); align-items: start;
}
.lp-bio__photo {
  aspect-ratio: 3 / 4; overflow: hidden; border-radius: 14px; background: var(--arbor-border);
}
.lp-bio__photo img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 12%; image-rendering: auto; }
.lp-bio__eyebrow {
  font-size: var(--lp-t-small); font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--lp-gold-dark);
}
.ui-modal .lp-bio__name {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1.5rem, 1.2rem + 1vw, 2.125rem); line-height: 1.1; letter-spacing: -0.015em;
  color: var(--lp-navy); margin-top: 7px; text-wrap: balance;
}
.ui-modal .lp-bio__rule { width: 42px; height: 3px; background: var(--lp-gold); border-radius: 3px; margin-block: 14px 21px; }
.lp-bio__copy { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; }
.lp-bio__p { font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem); line-height: 1.6; text-wrap: pretty; color: var(--arbor-text); max-width: 62ch; }
.ui-modal .lp-bio__cred {
  margin-top: 21px; padding-top: 14px; border-top: 1px solid var(--arbor-border);
  font-size: var(--lp-t-small); line-height: 1.5; color: var(--arbor-text-light); max-width: 62ch; text-wrap: pretty;
}

/* Phones: one column, the portrait above the words, everything centred.
   2026-09-14 (Quinten: "the pop up modals are off ... cut off on the right
   side"): these rules were written at ONE class and lost the cascade to the
   base rules above at TWO (`.ui-modal .ui-modal-body`), so the desktop grid
   survived on phones as `240px 87px` at 390 and `240px 47px` at 350, the
   words stood in a 47 to 87px tower against the right edge and ran off it at
   350, and WebKit sized the portrait 0 wide (measured in both engines). Every
   rule here now carries the `.ui-modal` prefix, and the portrait takes a
   real width instead of a max-width plus auto margins, which WebKit resolved
   to zero inside the grid cell. */
@media (max-width: 900px) {
  .ui-modal { padding: 0; align-items: end; }
  .ui-modal .ui-modal-container { max-height: 100dvh; width: 100%; border-radius: 14px 14px 0 0; }
  .ui-modal .ui-modal-body { grid-template-columns: minmax(0, 1fr); justify-items: center; }
  /* FIXED width AND height, no aspect-ratio: a grid item whose block size
     comes from aspect-ratio contributed ZERO to its auto row while the
     tracks were sized, in both engines, with a percentage width and with a
     fixed one (measured 2026-09-14: rows "0px 849px", the copy row started
     21px under the portrait's top and the name sat across the face; an
     explicit height read "195px 849px"). 260 x 195 is the 4:3 the phone
     layout wants, and it fits every phone from 302px up. */
  .ui-modal .lp-bio__photo { aspect-ratio: auto; width: 260px; height: 195px; max-width: 100%; margin-inline: auto; }
  .ui-modal .lp-bio__copy { align-items: center; text-align: center; width: 100%; }
  .ui-modal .lp-bio__rule { margin-inline: auto; }
  .ui-modal .lp-bio__p, .ui-modal .lp-bio__cred { max-width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .ui-modal-container, .ui-modal-close { transition: none; }
}
/* the page's BrokerCheck line, as a link under the credentials */
.ui-modal .lp-bio__check {
  display: inline-block; width: fit-content; margin-top: 9px;
  font-size: var(--lp-t-small); font-weight: 600; color: var(--lp-navy);
  text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--lp-gold);
  min-height: 49px; display: inline-flex; align-items: center; touch-action: manipulation;
}
@media (hover: hover) { .ui-modal .lp-bio__check:hover { color: var(--lp-gold-dark); } }

/* the modal's own scrollbar in the brand: thin gold thumb on a bare track.
   NOTE for the AG scrollbar port (ag-scrollbar.js, the gold rail): the page
   rail belongs to the document; this styles the modal body's native bar so
   the two never fight. Keep in mind when the rail is wired. */
.ui-modal .ui-modal-body { scrollbar-width: thin; scrollbar-color: var(--lp-gold) transparent; }
.ui-modal .ui-modal-body::-webkit-scrollbar { width: 9px; }
.ui-modal .ui-modal-body::-webkit-scrollbar-track { background: transparent; }
.ui-modal .ui-modal-body::-webkit-scrollbar-thumb { background: var(--lp-gold); border-radius: 9px; border: 2px solid var(--paper); }
/* while a modal is open the blurred page must not repaint every frame: the
   hero field, the trust ticker and the team strip hold still underneath */
body.has-modal .lp-dot, body.has-modal .lp-dot::after,
body.has-modal .lp-ticker__track, body.has-modal .lp-team__track { animation-play-state: paused; }
/* a closed modal keeps its portrait out of the layout entirely, so lazy
   loading holds it back until the modal opens (measured 2026-09-14: eight
   portraits, 400KB, were loading on a phone that never opened one) */
.ui-modal[hidden] img { display: none; }
