/*
 * Retreat landing — reusable bio dialog component (item I5, build-tracker.md)
 *
 * REVIEW ROUND 1, finding #7: this file now holds ONLY the reusable
 * `.retreat-bio-modal*` dialog component. Section 5's own styles
 * (`.retreat-guides*`) moved to assets/css/sections/retreat/guides.css — the
 * original single-file build kept both here on the (incorrect) premise that
 * no sections/retreat partial glob covered a new file; inc/enqueue.php's
 * `glob( 'assets/css/sections/retreat/*.css' )` (frozen since F1) in fact
 * auto-picks up any new file dropped into that directory. `bio-modal` is
 * still the literal name inc/enqueue.php's module foreach (CSS + JS,
 * page-gated, file_exists-guarded) watches for — no enqueue.php edit needed
 * for this file either.
 *
 * ── Bio modals (frames 93:335 Karen, 93:334 Peter) ──
 * Native <dialog>/showModal() (accessible-dialog brief: focus trap + Escape
 * + top-layer stacking for free, no polyfill). Card: white, radius 20 =
 * --radius-md exact, shadow = var(--shadow-card) (both match get_design_
 * context exactly: rounded-[20px] shadow-[0px_4px_20px_10px_rgba(0,0,0,.1)]),
 * max-width 1216px (comp 1213, same tolerance class as leave-with.css's
 * 1213-vs-1216 panel). Photo rect 369×384 (16:477 Karen / 93:307 Peter),
 * bg #e2e8ef = --color-grey-200 (LESSONS: styled placeholder panel,
 * aria-hidden, no photo assets supplied), radius comp 31px → nearest token
 * --radius-lg (24px, 7px tolerance — same adoption class as decision-log
 * #12's 22→24/34→32 roundings). Photo caption label ("KAREN"/"PETER",
 * 16:485 / 93:308) navy #1c2161, 22px = --font-xl, uppercase, centered —
 * folded into the aria-hidden photo block (redundant with the dialog's own
 * accessible name, same call as S8/S3's aria-hidden "VIDEO" caption).
 *
 * Name heading (93:330 Karen 30px / 93:310 Peter 30px, Rubik SemiBold, navy)
 * is an <h3> — nearest token --font-2xl (32px, 2px tolerance, same adoption
 * class as the rest of this build). Title Case ("Karen Bramhill"), so the
 * LESSONS h3 defensive counter applies: theme.json's h3 element style
 * compiles to `:root :where(h3)` (specificity 0,1,0 — :root contributes the
 * class-slot, :where() zeroes the element) which TIES a same-specificity
 * single-class selector; ties resolve by source order, and this stylesheet
 * loads after the inline global-styles block (enqueue.php), so
 * .retreat-bio-modal__name's own `text-transform: none; letter-spacing:
 * normal;` wins with no !important needed — identical mechanism to S3/S10's
 * fix, applied here for a Title Case (not lowercase) heading.
 *
 * Social icon (93:331 Karen / 93:311 Peter): get_design_context resolved
 * the referenced asset to a literal inline LinkedIn glyph (28×28 circle,
 * fill #02C17F = --color-success, white LinkedIn path) — reproduced as
 * inline SVG in the pattern file rather than an external asset. REVIEW
 * ROUND 1, finding #5: the SVG originally carried `fill="var(--...)"` as a
 * presentation attribute — unreliable in WebKit (falls back to black
 * instead of resolving the custom property). Fill is now set here via CSS
 * (`.retreat-bio-modal__social svg rect/path`) instead; the pattern file's
 * inline SVGs no longer set `fill` at all. No profile URL exists yet, so
 * both are stubbed `href="#"` (documented for C1 to wire the real profile
 * links) — browser verification for this build MUST NOT click these stubs
 * (href="#" triggers a same-page scroll-to-top with no meaningful
 * destination).
 *
 * TEDx logo (93:319, Peter only): get_design_context resolved this to a
 * real supplied PNG asset ("tedx-logo-png_seeklogo-303746") — SKIPPED per
 * the build brief (asset not supplied to this build). A styled, empty,
 * aria-hidden placeholder slot (.retreat-bio-modal__tedx-slot) is left in
 * the markup, sized to the comp's 60×21 box, for C1 to drop the real logo
 * into.
 *
 * Close buttons (93:326 Karen / 93:318 Peter): reproduced as inline SVG
 * (2-path X, comp stroke #1c2161 stroke-width 3) using `stroke="currentColor"`
 * so color routes through this file's `color` declaration, not a second
 * hardcoded hex.
 *
 * ── Dialog mechanism ──
 * Two <dialog> elements, shared JS (assets/js/bio-modal.js) driven by
 * data attributes (data-bio-modal-open / data-bio-modal-close), unique ids.
 * showModal() gives focus-into-dialog (browser default: first focusable
 * descendant, which is the close button here) and Escape-to-close for
 * free — no bespoke focus-trap or keydown code needed.
 *
 * Backdrop click (REVIEW ROUND 1, finding #2): a naive
 * `event.target === dialogEl` check misfires two ways — (a) at ≤768 the
 * full-height dialog's own empty area below the content IS the dialog, so
 * tapping it closed the modal; (b) a text selection ending with the
 * pointer released over the backdrop retargets the click to the dialog.
 * bio-modal.js now requires BOTH the `pointerdown` and the `click` to have
 * targeted the dialog element itself AND the click coordinates to fall
 * outside `dialog.getBoundingClientRect()` before closing — see that file's
 * header for the full mechanism.
 *
 * Body scroll lock (REVIEW ROUND 1, finding #1 — blocker): native <dialog>
 * does NOT prevent background scroll on its own (top-layer + modal
 * keyboard/click blocking only). The original build toggled
 * `.has-open-modal` on <body> alone and relied on `body { overflow: hidden }`
 * — INERT, because reset.css / global.css set `html, body { overflow-x:
 * clip }`, and overflow only propagates from body to the viewport when the
 * root element is visible on BOTH axes; with the root already pinned to
 * `clip` on the x-axis, the propagation swap never happens, so a class on
 * <body> alone styled a box that clips nothing and the page scrolled behind
 * the dialog. Fixed: bio-modal.js now toggles `.has-open-modal` on BOTH
 * <html> (below) and <body>, ref-counted so two dialogs opened in sequence
 * don't unlock early. `overscroll-behavior: contain` on `.retreat-bio-modal`
 * stops any residual scroll-chaining from a wheel/touch gesture inside the
 * dialog's own scrollable body reaching the locked page behind it. JS also
 * computes a scrollbar-width compensation custom property
 * (`--kdpc-scrollbar-comp`) so removing the vertical scrollbar doesn't
 * shift page content sideways while the lock is active.
 *
 * Close-button reachability (REVIEW ROUND 1, finding #3): the dialog itself
 * used to be the scroll container (`overflow-y: auto` on `.retreat-bio-
 * modal`) while `.retreat-bio-modal__close` was `position: absolute` inside
 * it — scrolling the dialog's content carried the close button off-screen
 * with it. Fixed by moving the scroll container to `.retreat-bio-modal__body`
 * (`min-height: 0` + `overflow-y: auto`, dialog itself is `display: flex;
 * flex-direction: column` with a fixed `max-height`) — the close button, a
 * sibling of `__body` and still `position: absolute` against the dialog's
 * own (non-scrolling) box, now stays put regardless of how far `__body`'s
 * content scrolls.
 *
 * ::backdrop (REVIEW ROUND 1, finding #6): was a hardcoded
 * `rgba(28, 33, 97, 0.55)` — the retreat-navy channels typed out by hand
 * with no token reference. Now `color-mix(in srgb, var(--color-retreat-navy)
 * 55%, transparent)`, so a navy token change (e.g. the pending #1C2161 vs
 * #26265F question) propagates here automatically instead of needing a
 * second hand-edit.
 *
 * Focus-return-to-opener is NOT a native behaviour — bio-modal.js stores
 * the triggering button and calls .focus() on the dialog's `close` event
 * (fires for both close() and native Escape/cancel).
 *
 * No entry animation, by design (not an oversight): trivially satisfies
 * prefers-reduced-motion with zero extra CSS, and avoids relying on
 * @starting-style (needed for animating native <dialog>/::backdrop open
 * transitions) whose browser-support floor is newer than the rest of this
 * theme's baseline. Focus trap + Escape + backdrop-close were the
 * accessibility requirements that actually mattered here; a fade-in was not.
 *
 * Mobile (≤768px) modal treatment is DERIVED, not comp-sourced (no mobile
 * frame exists — figma-analysis-2026-08.md "Design gaps"): full-bleed
 * card (no radius, no outer margin) with the photo/content columns
 * stacking, matching this theme's established ≤1024/≤768 card-stacking
 * convention (facilitator-cards.css, S8/S3 two-column sections). Flag for
 * designer review per the standing house rule on undesigned breakpoints.
 */

.retreat-bio-modal {
  position: fixed;
  inset: 0;
  margin: auto;
  max-width: 1216px; /* comp 1213 — same tolerance class as leave-with.css */
  width: calc(100% - var(--space-xs) * 2);
  max-height: calc(100dvh - var(--space-xl) * 2);
  border: none;
  border-radius: var(--radius-md); /* 20px — matches comp exactly */
  box-shadow: var(--shadow-card);
  background: var(--color-white);
  padding: 0;
  overscroll-behavior: contain; /* finding #1 — stop scroll-chaining to the locked page behind it */
}

/* `display` deliberately scoped to `[open]`, not the bare class (self-caught
 * during verification, finding #3's own fix): an author-origin rule always
 * beats a UA-origin rule regardless of specificity, so an unconditional
 * `.retreat-bio-modal { display: flex }` overrode the browser's own
 * `dialog:not([open]) { display: none }` and rendered a CLOSED dialog on
 * screen (visible, though non-modal — no ::backdrop, background click-
 * through). Scoping to `[open]` restores native hide-when-closed while
 * still getting the flex column layout finding #3 needs once it IS open.
 */
.retreat-bio-modal[open] {
  display: flex;
  flex-direction: column;
}

.retreat-bio-modal::backdrop {
  /* finding #6 — token-derived instead of a hand-typed rgba() */
  background: color-mix(in srgb, var(--color-retreat-navy) 55%, transparent);
}

.retreat-bio-modal__close {
  position: absolute;
  top: var(--space-sm);
  right: var(--space-sm);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px; /* touch-target floor */
  padding: 0;
  border: none;
  background: transparent;
  color: var(--color-retreat-navy);
  cursor: pointer;
}

.retreat-bio-modal__close svg {
  display: block;
  width: 20px;
  height: 19px;
}

/* :focus-visible intentionally NOT restated here (REVIEW ROUND 1, finding
   #8) — global.css:177's universal `:focus-visible { outline: 2px solid
   var(--color-primary); outline-offset: 2px; }` already applies to this
   button with identical values; a per-class duplicate is dead weight. */

.retreat-bio-modal__body {
  display: flex;
  gap: var(--space-md); /* comp column gap ~33-34px = --space-md */
  padding: var(--space-48) var(--space-64); /* comp top/left ~52/70px, same adoption tolerance as the rest of this build */
  overflow-y: auto; /* finding #3 — the dialog itself no longer scrolls, only this */
  min-height: 0; /* let this flex item actually shrink inside the dialog's max-height column */
}

.retreat-bio-modal__photo {
  position: relative;
  flex: 0 0 369px;
  aspect-ratio: 369 / 384;
  border-radius: var(--radius-lg); /* comp 31px, nearest token — 7px tolerance */
  background: var(--color-grey-200);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding-bottom: var(--space-lg);
}

/* Kickback round 1, finding #2 — real featured-image treatment, when the
   kdpc_bio post has one set (inc/cpt-bio.php's kdpc_bio_modal_shortcode()).
   Modest treatment per the orchestrator ruling: a smaller, contained radius
   (--radius-md, not the placeholder box's --radius-lg) and a max-width cap
   so a portrait or landscape upload both stay inside the column without
   fighting the placeholder's fixed 369×384 box — the image keeps its own
   intrinsic ratio instead of being cropped to match. */
.retreat-bio-modal__photo--image {
  aspect-ratio: auto;
  background: transparent;
  align-items: stretch;
  justify-content: stretch;
  padding-bottom: 0;
  max-width: 369px;
}

.retreat-bio-modal__photo-img {
  display: block;
  width: 100%;
  height: auto;
  max-width: 100%;
  border-radius: var(--radius-md);
}

/* Vertical bio video (Sara's 2026-08-20 ask, placed 2026-08-21): fills the
   photo slot; same intrinsic-ratio reasoning as --image above — the 9:16
   draft keeps its own ratio instead of being cropped to the 369×384
   placeholder box. */
.retreat-bio-modal__photo--video {
  aspect-ratio: auto;
  background: transparent;
  align-items: stretch;
  justify-content: stretch;
  padding-bottom: 0;
  max-width: 369px;
}

.retreat-bio-modal__video {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
}

.retreat-bio-modal__photo-label {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: var(--font-xl);
  text-transform: uppercase;
  text-align: center;
  color: var(--color-retreat-navy);
  margin: 0;
}

.retreat-bio-modal__content {
  flex: 1 1 auto;
  min-width: 0;
}

.retreat-bio-modal__name-row {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  margin: 0 0 var(--space-sm);
}

.retreat-bio-modal__name {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: var(--font-2xl); /* comp 30px, nearest token (32px) — 2px tolerance */
  line-height: 1.2;
  color: var(--color-retreat-navy);
  margin: 0;
  /* Defensive counter (LESSONS, S3/S10 precedent) — see file header. */
  text-transform: none;
  letter-spacing: normal;
}

.retreat-bio-modal__social {
  display: inline-flex;
  flex-shrink: 0;
}

.retreat-bio-modal__social svg {
  display: block;
  width: 28px;
  height: 28px;
}

/* finding #5 — fill moved here from the SVG's own `fill="var(--...)"`
   presentation attribute (unreliable in WebKit, falls back to black). */
.retreat-bio-modal__social svg rect {
  fill: var(--color-success);
}

.retreat-bio-modal__social svg path {
  fill: var(--color-white);
}

.retreat-bio-modal__tedx-slot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 21px;
  flex-shrink: 0;
}

.retreat-bio-modal__text {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs); /* 16px, matches comp's inter-paragraph margin */
}

.retreat-bio-modal__text p {
  font-family: var(--font-body);
  font-weight: var(--fw-regular);
  font-size: var(--font-md); /* comp 18px Karen / 16px Peter — shared token, 0-2px tolerance, same adoption class as elsewhere in this build */
  line-height: 1.55; /* theme.json global body default already matches the comp's ratio — no restatement needed */
  color: var(--color-text-body);
  margin: 0;
}

/* Body scroll lock while any dialog is open (bio-modal.js toggles these).
   Both <html> AND <body> get the class — finding #1, see file header. */
html.has-open-modal {
  overflow: hidden;
  padding-right: var(--kdpc-scrollbar-comp, 0px);
}

body.has-open-modal {
  overflow: hidden;
}

@media (max-width: 1024px) {
  .retreat-bio-modal__body {
    padding: var(--space-64) var(--space-48);
  }
}

@media (max-width: 768px) {
  /* Derived, no mobile frame exists (see file header) — full-bleed card,
     stacked columns. */
  .retreat-bio-modal {
    width: 100%;
    max-width: none;
    max-height: 100dvh;
    height: 100dvh; /* finding #8 nit — was 100%, dvh matches the max-height unit and dodges mobile URL-bar resize jumps */
    border-radius: 0;
  }

  .retreat-bio-modal__body {
    flex-direction: column;
    padding: var(--space-64) var(--space-xs) var(--space-xs);
  }

  .retreat-bio-modal__photo {
    flex-basis: auto;
    width: 100%;
    max-width: 320px;
    margin: 0 auto;
  }

  .retreat-bio-modal__close {
    top: var(--space-xs);
    right: var(--space-xs);
  }
}
