/* See ./product-feature-tiles.md for design notes, Figma token lock-in, and the
 * two-mode rendering contract. This stylesheet owns every BEM rule the
 * decorated DOM needs: section shell, grid sizing, per-tile face (top text
 * area + bottom media area + variant gradient fallback + open button), the
 * page-singleton .pft-modal overlay, and the popup body (kicker + title +
 * steps + plans + cta) rendered both inline (display: none in runtime) and
 * cloned into the modal frame. */

/* --- Section shell + heading + grid ----------------------------------- */

.product-feature-tiles__root {
  padding-block: var(--ll-space-9);
}

@media (width >= 1024px) {
  .product-feature-tiles__root {
    padding-block: var(--ll-space-13);
  }
}

.product-feature-tiles__heading {
  margin: 0 0 var(--ll-space-5);
  color: var(--ll-color-text-secondary);
  font-family: var(--ll-text-h5-family);
  font-size: var(--ll-text-h5-size);
  line-height: var(--ll-text-h5-line-height);
  letter-spacing: var(--ll-text-h5-letter-spacing);
  font-weight: var(--ll-text-h5-weight);
  text-align: left;
}

/* MD+ */
@media (width >= 768px) {
  .product-feature-tiles__heading {
    margin-block-end: var(--ll-space-5);
    font-family: var(--ll-text-h3-family);
    font-size: var(--ll-text-h3-size);
    line-height: var(--ll-text-h3-line-height);
    letter-spacing: var(--ll-text-h3-letter-spacing);
    font-weight: var(--ll-text-h3-weight);
  }
}

/* LG/XL */
@media (width >= 1024px) {
  .product-feature-tiles__heading {
    margin-block-end: calc(var(--ll-space-11) - var(--ll-space-6));
    text-align: center;
  }
}

.product-feature-tiles__grid {
  list-style: none;
  padding: 0;
  margin: 0;
  gap: var(--ll-space-5);
}

/* MD */
@media (width >= 768px) {
  .product-feature-tiles__grid {
    gap: var(--ll-space-8) var(--ll-space-6);
  }
}

/* LG/XL */
@media (width >= 1024px) {
  .product-feature-tiles__grid {
    gap: var(--ll-space-6);
  }
}

.product-feature-tiles__cell {
  display: flex;
  min-width: 0;
}

/* --- Tile face (gradient bg + title + description + open button) ------
 *
 * Selectors here are ordered shallow-to-deep so stylelint's
 * no-descending-specificity is satisfied: bare .product-feature-tile and
 * its bare BEM elements come first, then variant modifiers and
 * variant-scoped element overrides, then the cell > tile child-combinator
 * sizing rule (which is technically higher specificity than the bare
 * block selector). */

/* No `padding` on the tile itself. See "Face-media height rule" in
 * product-feature-tiles.md: the invariant `media.height = tile.height −
 * text-area.height` (and `media.width === tile.width`) requires that
 * only the text is inset; media must be free to bleed to the tile's
 * rounded outer edge on all four sides. The corresponding inset is
 * applied to `.product-feature-tile__face-text` further down. */
.product-feature-tile {
  /* Component-scoped hover motion.
   *
   * Deliberately does NOT read from --ll-motion-interactive-state-*.
   * Those are calibrated for buttons (220ms snappy). Card hover wants a
   * softer, slower feel (320ms classic ease) so the tile grows "molten"
   * rather than snapping. Matches the protection-section prototype.
   *
   * Kept component-scoped for now; promote to --ll-motion-card-* if a
   * second block wants the same feel. See "Motion" in
   * ./product-feature-tiles.md. */
  --pft-hover-duration: 320ms;
  --pft-hover-easing: cubic-bezier(0.25, 0.1, 0.25, 1);

  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 390px;

  /* 8px at every breakpoint. --ll-radius-card is the purpose-built semantic
   * token (aliases --ds-radius-l = 8px); prefer it over --ll-radius-md (6px)
   * or --ll-radius-l (also 8px but generic). */
  border-radius: var(--ll-radius-card);
  box-shadow: var(--ll-shadow-resting);
  overflow: hidden;
  isolation: isolate;

  /* Whole tile is a click target for pointer/touch users; cursor + hover
   * scale are the visual affordances. See "Interaction" in
   * ./product-feature-tiles.md for the full a11y contract. */
  cursor: pointer;
  transition: transform var(--pft-hover-duration) var(--pft-hover-easing);
}

.product-feature-tile:hover {
  transform: scale(1.02);
}

@media (width >= 768px) {
  .product-feature-tile {
    min-height: 462px;
  }
}

/* MD */
@media (width >= 768px) and (width < 1024px) {
  .product-feature-tile {
    height: 462px;
  }
}

/* Face is a strict top/bottom flex split:
 *   - __face-text (flex 0 0 auto): natural content height at the top
 *   - __face-media (flex 1 1 auto): fills the remaining tile height
 *
 * Gap between them, per the *canonical* Figma tile-face frames that
 * match the current authored content ("Scam / Identity / Financial /
 * Specialist"):
 *   - SM (`21207:2591`): 16 (`--ll-space-5`).
 *   - MD (`21066:5897`): 16 (falls through from SM base). Note Figma
 *     shows `gap-[44px]` on the tile flex container, but media is
 *     absolute-positioned at `top-[134px]` in that frame; text-area
 *     ends at y=118 so the visible text-to-media gap is 134-118 = 16.
 *     Do NOT switch to space-10 - that misreads the layout.
 *   - LG/XL (`21226:2818`): 24 (`--ll-space-7`). Media at y=166,
 *     text-area ends at y=142 -> gap 24. An earlier pass used the
 *     stale `20981:23045` frame (a different design iteration with
 *     "Fraud detection / Fixed by humans" copy) which measured 29;
 *     that frame does NOT match the authored content and is rejected. */
.product-feature-tile__face {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: var(--ll-space-5);
}

@media (width >= 1024px) {
  .product-feature-tile__face {
    gap: var(--ll-space-7);
  }
}

/* Padding lives here (not on the tile) so the media area below can bleed
 * to the tile's rounded outer edge on all four sides. `padding-block-end`
 * is intentionally zero — the `.face` flex `gap` between text and media
 * owns the visual breathing room below the text and is counted as part
 * of the "text-area" envelope, not carved out of media. */
.product-feature-tile__face-text {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--ll-space-4);
  padding: var(--ll-space-7) var(--ll-space-5) 0;
  max-width: 28ch;
}

@media (width >= 768px) {
  .product-feature-tile__face-text {
    gap: var(--ll-space-3);
    padding: var(--ll-space-8) var(--ll-space-6) 0;
    max-width: none;
  }
}

/* In Author (UE) mode, AEM wraps the richtext cell contents in a
 * `<div data-aue-prop="text">` for editability. buildFaceText moves that
 * wrapper into `.face-text`, which interrupts the flex chain — the `gap`
 * only applies between direct flex children, so the title/description
 * gap silently disappears. `display: contents` on the wrapper flattens
 * <h6> and <p> back into `.face-text`'s flex layout while preserving
 * the `data-aue-*` attributes UE needs to instrument the field.
 *
 * In EDS mode the AUE wrapper isn't emitted, so this rule
 * matches nothing and is a no-op — same pattern used by sticky-container,
 * l-split-sticky, testimonials, and value-proposition in this repo. */
.product-feature-tile__face-text > [data-aue-prop] {
  display: contents;
}

.product-feature-tile__title {
  margin: 0;
  font-family: var(--ll-text-h7-family);
  font-size: var(--ll-text-h7-size);
  line-height: var(--ll-text-h7-line-height);
  letter-spacing: var(--ll-text-h6-letter-spacing);
  font-weight: var(--ll-text-h7-weight);
}

@media (width >= 768px) {
  .product-feature-tile__title {
    font-family: var(--ll-text-h6-family);
    font-size: var(--ll-text-h6-size);
    line-height: var(--ll-text-h6-line-height);
    letter-spacing: var(--ll-text-h6-letter-spacing);
    font-weight: var(--ll-text-h6-weight);
  }
}

/* Description tier follows Figma tile-face token binding:
 * - SM (`21207:2591`): body-base variable resolves to 14/22 in tile-face mode
 *   -> LL body-sm (14/22).
 * - MD (`21066:5897`) and LG/XL (`20981:23045`): body-lg variable resolves to
 *   16/24 in tile-face mode -> LL body-base (16/24).
 * These are DIFFERENT resolutions from the popup context, where body-lg =
 * 18/26. Do not paper this over by using body-lg here. */
.product-feature-tile__desc {
  margin: 0;
  font-family: var(--ll-text-body-sm-family);
  font-size: var(--ll-text-body-sm-size);
  line-height: var(--ll-text-body-sm-line-height);
  letter-spacing: var(--ll-text-body-base-letter-spacing);
  font-weight: var(--ll-text-body-sm-weight);
}

@media (width >= 768px) {
  .product-feature-tile__desc {
    font-family: var(--ll-text-body-base-family);
    font-size: var(--ll-text-body-base-size);
    line-height: var(--ll-text-body-base-line-height);
    letter-spacing: var(--ll-text-body-lg-letter-spacing);
  }
}

/* Face-image treatment — three optional reference fields (image /
 * imageTablet / imageDesktop) are emitted by product-feature-tiles.js as a plain <picture>
 * with per-breakpoint <source media> tags, no ?width= optimization.
 *
 * The media area is an IN-FLOW flex child that fills whatever tile height
 * is left after the __face-text at the top; the image inside renders at
 * its NATURAL pixel size, BOTTOM-center aligned so the image sits flush
 * against the tile's rounded outer bottom edge. If the authored asset is
 * taller than the media area, the top of the image bleeds up toward the
 * text-area — the design contract is that authored assets match the
 * per-breakpoint media-area dimensions so this bleed never overlaps text.
 *
 * Consequence: authored assets are picked per breakpoint to match the
 * media-area dimensions Figma expects (SM 345x~250, MD 704x~350,
 * LG/XL 313x~350). See product-feature-tiles.md "Face-media height rule"
 * for the invariant and the per-breakpoint asset dimensions. */
.product-feature-tile__face-media {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  pointer-events: none;
}

/* MD- */
@media (width < 1024px) {
  .product-feature-tile__face-media {
    flex-grow: 1;
    min-height: 0;
    position: relative;
    width: 100%;
  }
}

.product-feature-tile__face-media picture,
.product-feature-tile__face-media img {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
}

/* MD- */
@media (width < 1024px) {
  .product-feature-tile__face-media picture {
    display: contents;
  }

  .product-feature-tile__face-media img {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
    max-width: none;
  }
}

.product-feature-tile--ivory {
  background: linear-gradient(
    150deg,
    var(--ll-color-bg-accent) 12%,
    var(--ll-color-bg-accent-warm) 84%
  );
  color: var(--ll-color-text-secondary);
}

.product-feature-tile--brand {
  background: linear-gradient(
    160deg,
    var(--ll-color-brand-primary) 26%,
    var(--ll-color-brand-secondary) 91%
  );
  color: var(--ll-color-text-inverse);
}

.product-feature-tile--ivory .product-feature-tile__title {
  color: var(--ll-color-text-secondary);
}

.product-feature-tile--ivory .product-feature-tile__desc {
  color: var(--ll-color-highlight-beta);
}

.product-feature-tile--brand .product-feature-tile__title,
.product-feature-tile--brand .product-feature-tile__desc {
  color: var(--ll-color-text-inverse);
}

.product-feature-tiles__cell > .product-feature-tile {
  width: 100%;
}

/* --- Open button ------------------------------------------------------- */

.product-feature-tile__open {
  position: absolute;
  top: var(--ll-space-4);
  right: var(--ll-space-4);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  background: var(--ll-color-bg-default);
  border: 1px solid var(--ll-color-border-default);
  border-radius: var(--ll-radius-pill);
  color: var(--ll-color-text-secondary);
  cursor: pointer;
}

@media (width >= 768px) {
  .product-feature-tile__open {
    top: var(--ll-space-5);
    right: var(--ll-space-5);
    width: 40px;
    height: 40px;
  }
}

.product-feature-tile__open:hover,
.product-feature-tile__open:focus-visible {
  background: var(--ll-color-bg-secondary-hover);
}

.product-feature-tile__open:focus-visible {
  outline: 2px solid var(--ll-color-border-focus);
  outline-offset: 2px;
}

/* buildCanonicalIcon emits <span class="icon product-feature-tile__open-icon">
 * with the SVG URL pinned via --pft-open-icon-url. Mask + currentcolor tints
 * the glyph with the button color. */
.product-feature-tile__open-icon {
  display: inline-flex;
  width: 20px;
  height: 20px;
  background-color: currentcolor;
  mask: var(--pft-open-icon-url) center / contain no-repeat;

  /* stylelint-disable-next-line property-no-vendor-prefix --
     Safari < 15.4 still requires the -webkit-mask shorthand. */
  -webkit-mask: var(--pft-open-icon-url) center / contain no-repeat;
}

@media (width >= 768px) {
  .product-feature-tile__open-icon {
    width: 24px;
    height: 24px;
  }
}

.product-feature-tile__open-icon > img {
  display: none;
}

/* ---- Modal overlay (.pft-modal) ---- */

.pft-modal {
  --pft-sheet-duration: 480ms;
  --pft-sheet-easing: cubic-bezier(0.32, 0.72, 0, 1);
  --pft-backdrop-duration: 480ms;
  --pft-backdrop-easing: var(--pft-sheet-easing);
  --pft-sheet-radius: 24px;

  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

.pft-modal[hidden] {
  display: none;
}

.pft-modal__backdrop {
  position: absolute;
  inset: 0;
  background: transparent;
  backdrop-filter: blur(0);
  transition:
    background var(--pft-backdrop-duration) var(--pft-backdrop-easing),
    backdrop-filter var(--pft-backdrop-duration) var(--pft-backdrop-easing);
}

.pft-modal--open .pft-modal__backdrop {
  background: var(--ll-color-bg-scrim);
  backdrop-filter: blur(2px);
}

.pft-modal--closing .pft-modal__backdrop {
  background: transparent;
  backdrop-filter: blur(0);
}

.pft-modal__frame {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 100%;
  height: auto;
  max-height: 92dvh;
  overflow: hidden;
  background: var(--ll-color-bg-default);
  border-radius: var(--pft-sheet-radius) var(--pft-sheet-radius) 0 0;
  opacity: 1;
  transform: translateY(100%);
  transition: transform var(--pft-sheet-duration) var(--pft-sheet-easing);
  will-change: transform;
}

.pft-modal__frame:focus,
.pft-modal__frame:focus-visible {
  outline: none;
}

.pft-modal--open .pft-modal__frame {
  transform: translateY(0);
}

.pft-modal--closing .pft-modal__frame {
  transform: translateY(100%);
}

.pft-modal--dragging .pft-modal__frame {
  transition: none;
}

/* Sheet chrome */
.pft-modal__sheet-header {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 0 0 auto;
  align-items: stretch;
  padding-block: var(--ll-space-3);
  padding-inline: var(--ll-space-5);
  background: var(--ll-color-bg-default);
  touch-action: none;
}

.pft-modal__drag-handle {
  align-self: center;
  width: 44px;
  height: 4px;
  margin-block-end: var(--ll-space-4);
  border-radius: var(--ll-radius-pill);
  background: var(--ll-color-border-default);
}

.pft-modal__sheet-eyebrow {
  min-width: 0;
  min-height: var(--ll-text-body-base-line-height);
  margin-block-start: var(--ll-space-3);
  padding-inline-end: var(--ll-space-9);
}

.pft-modal__sheet-eyebrow:empty {
  display: none;
}

/* Sheet body fills the frame but no longer scrolls itself — the inner
 * `.product-feature-tile__popup-scroll` region owns scrolling now so the
 * kicker/title header and the CTA stay pinned (WEBEXP-110878). */
.pft-modal__sheet-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  overscroll-behavior: none;
}

.pft-modal__sheet-footer {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 24px;
  pointer-events: none;
}

.pft-modal__sheet-home-indicator {
  width: 134px;
  height: 5px;
  border-radius: var(--ll-radius-pill);
  background: var(--ll-color-border-default);
}

/* Close — SM */
.pft-modal__close {
  position: absolute;
  top: var(--ll-space-5);
  right: var(--ll-space-5);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  padding: 0;
  background: transparent;
  border: 1px solid var(--ll-color-border-default);
  border-radius: var(--ll-radius-pill);
  color: var(--ll-color-text-secondary);
  cursor: pointer;
}

.pft-modal__close:focus-visible {
  outline: 2px solid var(--ll-color-border-focus);
  outline-offset: 2px;
}

.pft-modal__close-icon {
  display: inline-flex;
  width: 24px;
  height: 24px;
  background-color: currentcolor;
  mask: var(--pft-modal-close-icon-url) center / contain no-repeat;

  /* stylelint-disable-next-line property-no-vendor-prefix --
     Safari < 15.4 still requires the -webkit-mask shorthand. */
  -webkit-mask: var(--pft-modal-close-icon-url) center / contain no-repeat;
}

.pft-modal__close-icon > img {
  display: none;
}

/* MD */
@media (width >= 768px) {
  .pft-modal {
    --pft-enter-easing: cubic-bezier(0.25, 0.1, 0.25, 1);
    --pft-enter-duration-opacity: 250ms;
    --pft-enter-duration-transform: 300ms;
    --pft-exit-easing: cubic-bezier(0.4, 0, 1, 1);
    --pft-exit-duration-opacity: 200ms;
    --pft-exit-duration-transform: 220ms;
    --pft-backdrop-duration: 280ms;
    --pft-backdrop-easing: cubic-bezier(0.25, 0.1, 0.25, 1);

    align-items: center;

    /* Responsive inset — see product-feature-tiles.md "Overlay viewport fit (WEBEXP-110878)". */
    --pft-modal-inset: clamp(var(--ll-space-4), 2.1dvh, var(--ll-space-9));

    padding: var(--pft-modal-inset);
  }

  .pft-modal__frame {
    width: 100%;
    max-width: 538px;
    max-height: calc(100dvh - (var(--pft-modal-inset) * 2));
    border-radius: var(--ll-radius-lg);
    box-shadow: var(--ll-shadow-overlay);
    opacity: 0;
    transform: scale(0.96);
    transition:
      opacity var(--pft-enter-duration-opacity) var(--pft-enter-easing),
      transform var(--pft-enter-duration-transform) var(--pft-enter-easing);
    will-change: transform, opacity;
  }

  .pft-modal--open .pft-modal__frame {
    opacity: 1;
    transform: scale(1);
  }

  .pft-modal--closing .pft-modal__frame {
    opacity: 0;
    transform: scale(0.97);
    transition:
      opacity var(--pft-exit-duration-opacity) var(--pft-exit-easing),
      transform var(--pft-exit-duration-transform) var(--pft-exit-easing);
  }

  .pft-modal__sheet-header {
    position: absolute;
    inset: 0 0 auto;
    z-index: 2;
    display: block;
    height: 0;
    padding: 0;
    overflow: visible;
    pointer-events: none;
  }

  .pft-modal__drag-handle,
  .pft-modal__sheet-eyebrow,
  .pft-modal__sheet-footer {
    display: none;
  }

  .pft-modal__close {
    position: absolute;
    top: var(--ll-space-6);
    right: var(--ll-space-6);
    width: 40px;
    height: 40px;
    pointer-events: auto;
    background: var(--ll-color-bg-default);
    border: 1px solid var(--ll-color-border-default);
    border-radius: var(--ll-radius-pill);
  }

  .pft-modal__close-icon {
    width: 32px;
    height: 32px;
  }
}

/* LG/XL */
@media (width >= 1024px) {
  .pft-modal {
    --pft-modal-inset: clamp(var(--ll-space-4), 2.1dvh, var(--ll-space-14));
  }

  .pft-modal__frame {
    max-width: 980px;
  }
}

/* --- Detail region (hidden in runtime, rendered inside .pft-modal on
 *     click, or force-shown by the detail-preview fixture) -------------
 *
 * Rules below intentionally use unscoped `.product-feature-tile__popup-*`
 * selectors  the popup INNER chrome (typography, spacing, colors, plan
 * pills, steps) must render correctly whether the container is `.pft-modal`,
 * a QA fixture (`[data-detail-preview]`), or the eventual `.l-modal` frame.
 * Only the visibility toggle (`display: none`  `display: flex`) is
 * container-scoped. Container-specific chrome (backdrop, width caps, close
 * button placement, bottom-sheet drag handles) belongs to the container,
 * not this rule set. See product-feature-tiles.md for the design lock-in
 * table and the Figma frame references. */

.product-feature-tile__popup {
  display: none;
  flex-direction: column;
  background: var(--ll-color-bg-default);
  overflow: hidden;
}

/* Container-scoped show toggle. The popup now FILLS the frame (up to its
 * max-height) so the inner `.product-feature-tile__popup-scroll` region can be
 * the scroll container — kicker/title/CTA stay pinned (WEBEXP-110878). The
 * frame still shrink-wraps to content below max-height, so short overlays keep
 * their natural, non-scrolling composition. */
.pft-modal .product-feature-tile__popup {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
}

/* Radius at MD+ only — SM radius lives on .pft-modal__frame top corners. */
@media (width >= 768px) {
  .product-feature-tile__popup {
    border-radius: var(--ll-radius-lg);
  }
}

@media (width >= 1024px) {
  .product-feature-tile__popup {
    flex-direction: row;
    align-items: stretch;
  }
}

/* Image column: hidden at SM+MD (single-column per Figma); revealed at
 * LG/XL as a fixed 442-wide rail matching the frame split (442 + 538). */
.product-feature-tile__popup-image {
  display: none;
}

@media (width >= 1024px) {
  /* The image is a background rail: it must CROP to the content column's
     height, never dictate it. Absolutely-filling the picture/img takes them
     out of flow so the row height is driven by the (compressible) body, and
     the image crops via object-fit: cover. See product-feature-tiles.md
     "Overlay viewport fit (WEBEXP-110878)". */
  .product-feature-tile__popup-image {
    position: relative;
    display: block;
    flex: 0 0 442px;
    width: 442px;
    min-height: 520px;
    overflow: hidden;
  }

  /* Inside the modal the rail must never force the frame taller than its
     max-height: drop the 520 floor so it stretches to the (capped) popup
     height and crops via object-fit (WEBEXP-110878). */
  .pft-modal .product-feature-tile__popup-image {
    min-height: 0;
  }

  .product-feature-tile__popup-image > picture {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
  }

  .product-feature-tile__popup-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}

/* Popup body padding is breakpoint-tiered:
 *   SM: 16 (Figma bottom-sheet content inset = ~15px). Padding stays
 *       narrow to preserve horizontal room in the 375-wide sheet.
 *   MD+: 40 (Figma MD/LG frame inset).
 * `--pft-popup-gap` (default --ll-space-8 = 32) is the base flex `gap`. Outside
 * the modal it stays a constant 32; inside `.pft-modal` at MD+ it is compressed
 * responsively via clamp (WEBEXP-110878) to help the overlay fit shorter
 * viewports. Every child that needs a different visible gap carries its own
 * negative-`margin-block-start` calc that subtracts `var(--pft-popup-gap)` (see
 * kicker+title, section-label + steps/plans, plans-list + CTA overrides below),
 * so those tuned gaps hold as the base gap compresses. */
.product-feature-tile__popup-body {
  --pft-popup-gap: var(--ll-space-8);

  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--pft-popup-gap);
  padding: var(--ll-space-5);
  min-width: 0;
  min-height: 0;
}

@media (width < 768px) {
  .pft-modal .product-feature-tile__popup-body {
    padding-block-start: 0;
  }
}

@media (width >= 768px) {
  .product-feature-tile__popup-body {
    padding: var(--ll-space-9);
  }

  /* Responsive body rhythm — see product-feature-tiles.md "Overlay viewport fit (WEBEXP-110878)". */
  .pft-modal .product-feature-tile__popup-body {
    --pft-popup-gap: clamp(var(--ll-space-4), 1.6dvh, var(--ll-space-8));

    padding-block: clamp(var(--ll-space-4), 1.8dvh, var(--ll-space-9));
  }

  /* Step rows tighten their vertical padding on shorter viewports too. */
  .pft-modal .product-feature-tile__step {
    padding-block: clamp(var(--ll-space-3), 1.3dvh, var(--ll-space-5));
  }

  .pft-modal .product-feature-tile__step::before {
    inset-block-start: clamp(var(--ll-space-3), 1.3dvh, var(--ll-space-5));
  }
}

/* Popup-body is `align-items: center` so the shrink-wrapped CTA button
 * centers horizontally without wrapper DOM. Every full-width child
 * (kicker, title, section labels, steps, plans) must stretch back to
 * fill the content column. */
.product-feature-tile__popup-kicker,
.product-feature-tile__popup-title,
.product-feature-tile__popup-scroll,
.product-feature-tile__popup-section-label,
.product-feature-tile__steps,
.product-feature-tile__plans {
  align-self: stretch;
  width: 100%;
}

/* Middle scroll region (WEBEXP-110878): groups the steps + plans so only they
 * scroll on short viewports while kicker + title (above) and the CTA (below)
 * stay pinned as fixed flex children of popup-body. `gap` mirrors
 * `--pft-popup-gap` so the section-label/list negative-margin calcs (which
 * subtract that same var) net the identical Figma gaps they did when these were
 * direct popup-body children. See ./product-feature-tiles.md. */
.product-feature-tile__popup-scroll {
  display: flex;
  flex-direction: column;
  gap: var(--pft-popup-gap);
  min-width: 0;
}

/* Only inside the modal does the middle become a real scroller. `flex: 0 1 auto`
 * lets it shrink-to-fit when the overlay fits (CTA hugs the content, no scroll)
 * and shrink + scroll internally when the frame hits its max-height. */
.pft-modal .product-feature-tile__popup-scroll {
  flex: 0 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: none;

  /* stylelint-disable-next-line property-no-vendor-prefix --
     iOS Safari momentum scroll inside the middle region. */
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--ll-color-text-tertiary) 40%, transparent) transparent;
}

.product-feature-tile__popup-kicker {
  margin: 0;
  color: var(--ll-color-text-muted);
  font-family: var(--ll-text-body-base-family);
  font-size: var(--ll-text-body-base-size);
  line-height: var(--ll-text-body-base-line-height);
  letter-spacing: var(--ll-text-body-lg-letter-spacing);
  font-weight: var(--ds-font-weight-medium);
}

@media (width >= 768px) {
  .product-feature-tile__popup-kicker {
    font-family: var(--ll-text-body-xl-family);
    font-size: var(--ll-text-body-xl-size);
    line-height: var(--ll-text-body-xl-line-height);
    letter-spacing: var(--ll-text-body-xl-letter-spacing);
  }
}

.product-feature-tile__popup-title {
  margin: 0;
  color: var(--ll-color-text-secondary);
  font-family: var(--ll-text-h6-family);
  font-size: var(--ll-text-h6-size);
  line-height: var(--ll-text-h6-line-height);
  letter-spacing: var(--ll-text-h5-letter-spacing);
  font-weight: var(--ll-text-h6-weight);
}

@media (width >= 768px) {
  .product-feature-tile__popup-title {
    font-family: var(--ll-text-h5-family);
    font-size: var(--ll-text-h5-size);
    line-height: var(--ll-text-h5-line-height);
    letter-spacing: var(--ll-text-h5-letter-spacing);
    font-weight: var(--ds-font-weight-medium);
  }
}

/* Kicker + title net a 16px gap. Popup-body's own `gap: --ll-space-8`
 * (32) sits between every pair of children by default; the title's
 * negative block-start margin cancels 16 of that so the visible
 * kicker->title distance matches the Figma header block. Same
 * negative-calc pattern used by the plans-label / plans-list / cta
 * overrides below. */
.product-feature-tile__popup-kicker + .product-feature-tile__popup-title {
  margin-block-start: calc(var(--ll-space-5) - var(--pft-popup-gap));
}

/* At SM the Figma bottom-sheet spec adds a hairline divider between the
 * kicker row and the title (`21090:33501` "HorizontalBorder"). MD+/LG
 * keep the kicker + title tightly stacked without a divider (the
 * two-column LG layout carries its own visual separation via the image
 * column), so the divider is SM-only.
 *
 * Math (SM):
 *   - Base rule above already pulls title box up by 16 via
 *     `margin-block-start: calc(space-5 - space-8)`  title-box top sits
 *     at kicker-bottom + 16.
 *   - `border-block-start: 1px` renders the hairline at title-box top =
 *     kicker-bottom + 16. Kicker->border reads as 16.
 *   - `padding-block-start: --ll-space-5` (16) then pushes the title
 *     text 16 below the border.
 *   - Result: "kicker | 16 | ---- | 16 | title". Adds 17 to title's
 *     start position vs. non-SM (border + 16 padding), which is
 *     absorbed into the scroll region. */
@media (width < 768px) {
  .product-feature-tile__popup-kicker + .product-feature-tile__popup-title {
    padding-block-start: var(--ll-space-5);
    border-block-start: 1px solid var(--ll-color-border-default);
  }
}

/* Author-mode AUE-wrapper flatten (same idiom used for .face-text above).
 *
 * In Author (UE) mode, AEM instruments richtext fields by wrapping their
 * emitted content in an inner block element that carries `data-aue-*`
 * attributes. For the popup title the emitted DOM is:
 *
 *   <h2 class="__popup-title">
 *     <p data-aue-prop="popupHeading">Your identity, secured</p>
 *   </h2>
 *
 * The inner <p> inherits the global `p { margin-top: 12.8px;
 * margin-bottom: 4px }` from styles/styles.css and stretches the <h2>
 * from its intended 34 (line-height h5) to ~51. `display: contents`
 * removes the wrapper from the layout tree while preserving its
 * `data-aue-*` attributes so Universal Editor still instruments the
 * field for inline editing. In EDS mode AEM does NOT emit
 * the AUE wrapper, so the selector matches nothing and this rule is a
 * no-op.
 *
 * Applied broadly to every authored popup text surface (title, kicker,
 * section labels) so the fix is durable if any of them are switched
 * from plain-text to richtext in the future. Not applied to `.step`
 * or `.plan` <li>s -- their AUE wrappers (if any) live at the row
 * level and MUST stay in the layout tree, since product-feature-tiles.js relies on the
 * <li> box for the numbered-step chip counter and the plan pill flex
 * layout. */
.product-feature-tile__popup-title > p,
.product-feature-tile__popup-title > [data-aue-prop],
.product-feature-tile__popup-kicker > [data-aue-prop],
.product-feature-tile__popup-section-label > [data-aue-prop] {
  display: contents;
}

/* Section labels render like a section-level kicker (accent color, medium
 * weight). Two flavors: "How it works" sits above the steps with no top
 * separator (the first step border acts as the divider); "Included in"
 * gets a 32-pad-top + hairline border-block-start so the "plans" block
 * visually separates from the "steps" block above.
 *
 * Typography is tiered: at SM the label reads at 16/24 medium (Figma
 * bottom-sheet body-lg equivalent; LL `body-base` = 16/24 = Figma
 * `body-lg` in absolute pixels — see LL vs Figma token scale note in
 * `product-feature-tiles.md`). At MD+ it grows to LL `body-xl` (20/30)
 * to match the larger LG frame. Previously SM used LL `h6` (24) which
 * was oversized vs. Figma SM. */
.product-feature-tile__popup-section-label {
  margin: 0;
  color: var(--ll-color-text-muted);
  font-family: var(--ll-text-body-base-family);
  font-size: var(--ll-text-body-base-size);
  line-height: var(--ll-text-body-base-line-height);
  letter-spacing: var(--ll-text-body-lg-letter-spacing);
  font-weight: var(--ds-font-weight-medium);
}

@media (width >= 768px) {
  .product-feature-tile__popup-section-label {
    font-family: var(--ll-text-body-xl-family);
    font-size: var(--ll-text-body-xl-size);
    line-height: var(--ll-text-body-xl-line-height);
    letter-spacing: var(--ll-text-body-xl-letter-spacing);
  }
}

/* --- Steps (numbered "How it works" list) ----------------------------- */

.product-feature-tile__steps {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: pft-step;
}

/* Step layout: relative box with padding-inline-start reserving space for
 * an absolute-positioned CSS-counter number chip. Using grid + `> *` to
 * reassign column would leave text-node children (the description prose
 * that follows the authored <strong> title) stranded in the number
 * column, since `> *` matches ELEMENTS only. Padding + absolute keeps the
 * authored <li>'s mixed strong+text content flowing naturally.
 * The bare description text inherits this color; the <strong> title and
 * the ::before number chip set their own full-opacity color, so the 80%
 * color-mix here lands only on the description (Figma Opacity-80 on
 * Color/Content/secondary). See ./product-feature-tiles.md "Steps". */
.product-feature-tile__step {
  position: relative;
  padding: var(--ll-space-5) 0 var(--ll-space-5) calc(36px + var(--ll-space-5));
  border-top: 1px solid var(--ll-color-border-default);
  counter-increment: pft-step;
  color: color-mix(in srgb, var(--ll-color-text-secondary) 80%, transparent);
  font-family: var(--ll-text-body-sm-family);
  font-size: var(--ll-text-body-sm-size);
  line-height: var(--ll-text-body-sm-line-height);
  letter-spacing: var(--ll-text-body-sm-letter-spacing);
  font-weight: var(--ll-text-body-sm-weight);
}

@media (width >= 768px) {
  .product-feature-tile__step {
    font-family: var(--ll-text-body-base-family);
    font-size: var(--ll-text-body-base-size);
    line-height: var(--ll-text-body-base-line-height);
    letter-spacing: var(--ll-text-body-base-letter-spacing);
    font-weight: var(--ll-text-body-base-weight);
  }
}

/* Note: previously `border-top: 0` was applied to the first step so the
 * step block sat flush against the "How it works" section label with no
 * visible separator. Figma bottom-sheet spec (`21090:33501`) shows a
 * hairline divider between the section label and step 1 (matches the
 * design lock-in table's "first step's border is the divider" note). We
 * keep step 1's top border on all breakpoints so that separator renders. */

/* CSS-counter step number: renders "01 / 02 / 03" from Figma without
 * mutating the authored <li> body. Uses h6 typography at SM (24/30) and
 * h5 at MD+ (28/34) to match the Figma number chip. Positioned so its
 * top aligns with the step's padding-top. */
.product-feature-tile__step::before {
  content: counter(pft-step, decimal-leading-zero);
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: var(--ll-space-5);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  color: var(--ll-color-text-secondary);
  font-family: var(--ll-text-h6-family);
  font-size: var(--ll-text-h6-size);
  line-height: var(--ll-text-h6-line-height);
  letter-spacing: var(--ll-text-h5-letter-spacing);
  font-weight: var(--ll-text-h6-weight);
}

@media (width >= 768px) {
  .product-feature-tile__step::before {
    font-family: var(--ll-text-h5-family);
    font-size: var(--ll-text-h5-size);
    line-height: var(--ll-text-h5-line-height);
    letter-spacing: var(--ll-text-h5-letter-spacing);
    font-weight: var(--ds-font-weight-medium);
  }
}

.product-feature-tile__step > strong {
  display: block;
  margin-block-end: var(--ll-space-2);
  color: var(--ll-color-text-secondary);
  font-family: var(--ll-text-body-base-family);
  font-size: var(--ll-text-body-base-size);
  line-height: var(--ll-text-body-base-line-height);
  letter-spacing: var(--ll-text-body-lg-letter-spacing);
  font-weight: var(--ds-font-weight-medium);
}

@media (width >= 768px) {
  .product-feature-tile__step > strong {
    font-family: var(--ll-text-body-lg-family);
    font-size: var(--ll-text-body-lg-size);
    line-height: var(--ll-text-body-lg-line-height);
    letter-spacing: var(--ll-text-body-lg-letter-spacing);
  }
}

/* --- Plans ("Included in" pill overlays) ------------------------------ */

/* Inter-pill gap is tiered: 4 at SM (Figma bottom-sheet 3-pill stack
 * height 122 = 3x38 + 2x4), 8 at MD+ (LG spec observes the wider gap
 * in the 458-wide plans block). */
.product-feature-tile__plans {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--ll-space-2);
}

@media (width >= 768px) {
  .product-feature-tile__plans {
    gap: var(--ll-space-3);
  }
}

.product-feature-tile__popup-section-label + .product-feature-tile__steps,
.product-feature-tile__popup-section-label--plans + .product-feature-tile__plans {
  margin-block-start: calc(var(--ll-space-3) - var(--pft-popup-gap));
}

@media (width >= 768px) {
  .product-feature-tile__popup-section-label + .product-feature-tile__steps,
  .product-feature-tile__popup-section-label--plans + .product-feature-tile__plans {
    margin-block-start: calc(var(--ll-space-5) - var(--pft-popup-gap));
  }
}

/* Plan overlay pill:
 *   min-height  38px SM, 46px MD+ (Figma nominal height; content is allowed
 *                to push taller if body-lg line-height at MD exceeds the
 *                content area, which is expected).
 *   radius      --ll-radius-card (8px). Common name-vs-value trap:
 *                --ll-radius-md is 6px, not 8px. Grep-verified in
 *                styles/styles.css lines 375-388.
 *   bg          --ll-color-bg-muted (#f8f8f7). Not --ll-color-bg-secondary
 *                (#fafafc). Same trap: Figma's "Color/Background/secondary"
 *                resolves to the same hex as LL's bg-muted, not bg-secondary. */
.product-feature-tile__plan {
  --pft-plan-benefit-color: #005128;

  display: flex;
  align-items: baseline;
  gap: var(--ll-space-2);
  box-sizing: border-box;
  min-height: 34px;
  padding: var(--ll-space-3) var(--ll-space-4);
  background: var(--ll-color-bg-muted);
  border-radius: var(--ll-radius-card);
  color: var(--ll-color-text-secondary);
}

@media (width >= 768px) {
  .product-feature-tile__plan {
    min-height: 50px;
    padding: var(--ll-space-4);
  }
}

/* Natural width (not flex-grow) so Core + price cluster on the LEFT, matching
 * Figma. Badge + check are pushed to the RIGHT via `margin-inline-start: auto`
 * on the first of them (see the `> em, > s, > del` rule below). */
.product-feature-tile__plan > strong {
  flex: 0 0 auto;
  font-family: var(--ll-text-body-base-family);
  font-size: var(--ll-text-body-base-size);
  line-height: var(--ll-text-body-base-line-height);
  letter-spacing: var(--ll-text-body-base-letter-spacing);
  font-weight: var(--ds-font-weight-medium);
}

@media (width >= 768px) {
  .product-feature-tile__plan > strong {
    font-family: var(--ll-text-body-lg-family);
    font-size: var(--ll-text-body-lg-size);
    line-height: var(--ll-text-body-lg-line-height);
    letter-spacing: var(--ll-text-body-lg-letter-spacing);
  }
}

/* Price-line surround: <em> in a plan. Wraps the whole "from $X.XX/mo."
 * run with the dp-link nested inside. Reads greyish (Figma
 * "Color/Disabled/primary" = #888887) at body-xs / medium, matching the
 * muted price treatment across all four tile popups. Un-italicised via
 * font-style: normal (RTE Italic is repurposed as a semantic wrapper, not
 * a visual italic). The nested <a> and its post-DP replacement (a
 * <span class="dp-element">) inherit typography + color from here; only
 * text-decoration is fixed separately (see rule below). See ./product-feature-tiles.md
 * "Plan pill authoring" for the surround/badge structural invariant. */
.product-feature-tile__plan > em {
  flex: 0 0 auto;
  font-style: normal;
  color: var(--ll-color-text-disabled);
  font-family: var(--ll-text-body-xs-family);
  font-size: var(--ll-text-body-xs-size);
  line-height: var(--ll-text-body-xs-line-height);
  letter-spacing: var(--ll-text-body-xs-letter-spacing);
  font-weight: var(--ds-font-weight-medium);
}

/* dp-link (before DP) and dp-element <span> (after DP) both live INSIDE the
 * surround <em> now, so typography + color inherit. Only kill the UA anchor
 * underline and force `color: inherit` (DP writes textContent, not color, so
 * this is defensive against future ancestor rules bleeding blue in). */
.product-feature-tile__plan a,
.product-feature-tile__plan .dp-element {
  text-decoration: none;
  color: inherit;
}

/* Positive-plan badge: <u>. Authored via the RTE Underline button (see
 * models/_richtext.json toolbar). We kill the UA underline via
 * text-decoration: none so the tag reads as a pure structural marker — the same
 * repurpose pattern we use on <em> (font-style: normal) and <del>
 * (text-decoration: none). Colour is --pft-plan-benefit-color (Figma
 * brand/trustpilot/logo-shadow = #005128), the a11y-passing dark green shared
 * with the trailing ::after check (WEBEXP-110879 — was
 * --ll-color-status-success-strong #146e3c). `margin-inline-start: auto` is the right-align mechanism:
 * <strong> and the surround <em> hug the left at their natural widths;
 * this auto margin eats the remaining space so the badge (and the
 * trailing ::after check) sit on the right edge of the pill. Same
 * mechanism on the negative <s>/<del> below so the negative-plan variant
 * keeps the same horizontal split. */
.product-feature-tile__plan > u {
  flex: 0 0 auto;
  align-self: center;
  margin-inline-start: auto;
  text-decoration: none;
  color: var(--pft-plan-benefit-color);
  font-family: var(--ll-text-body-xs-family);
  font-size: var(--ll-text-body-xs-size);
  line-height: var(--ll-text-body-xs-line-height);
  letter-spacing: var(--ll-text-body-xs-letter-spacing);
}

/* Negative-plan badge: <s> / <del>. See ./product-feature-tiles.md "Plan pill
 * authoring" and "Plan row parity (WEBEXP-110372)". */
.product-feature-tile__plan > s,
.product-feature-tile__plan > del {
  flex: 0 0 auto;
  align-self: center;
  margin-inline-start: auto;
  color: color-mix(in srgb, var(--ll-color-text-secondary) 60%, transparent);
  font-family: var(--ll-text-body-xs-family);
  font-size: var(--ll-text-body-xs-size);
  line-height: var(--ll-text-body-xs-line-height);
  letter-spacing: var(--ll-text-body-xs-letter-spacing);
  font-style: normal;
  text-decoration: none;
}

/* Checkmark rendered via mask so no DOM mutation of the authored <li> is
 * required. Absolute URL is fine for EDS mode because :4501 serves from the
 * same origin. Fill = --pft-plan-benefit-color. See ./product-feature-tiles.md
 * "Plan row parity (WEBEXP-110372)". */
.product-feature-tile__plan::after {
  content: '';
  flex: 0 0 auto;
  align-self: center;
  display: inline-block;
  width: 16px;
  height: 16px;
  background-color: var(--pft-plan-benefit-color);
  mask: url('/icons/status/simple-checkmark.svg') center / contain no-repeat;

  /* stylelint-disable-next-line property-no-vendor-prefix --
     Safari < 15.4 still requires the -webkit-mask shorthand. */
  -webkit-mask: url('/icons/status/simple-checkmark.svg') center / contain no-repeat;
}

.product-feature-tile__plan--no-check::after {
  content: none;
}

/* --- Detail CTA ------------------------------------------------------- */

/* CTA wrapper. `p.` qualifier + negative block-start margin manage the
 * plans-to-CTA gap; MD+ centers the shrink-wrapped button per canonical Figma.
 * See ./product-feature-tiles.md "See all plans CTA (WEBEXP-110372)". */
p.product-feature-tile__popup-cta {
  --pft-cta-radius: 30px;

  align-self: stretch;
  margin: 0;
  margin-block-start: calc(var(--ll-space-7) - var(--pft-popup-gap));
}

p.product-feature-tile__popup-cta > a.button {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 44px;
  padding: 0 var(--ll-space-5);
  border: 1px solid var(--ll-color-border-inverse);
  border-radius: var(--pft-cta-radius);
  background: var(--ll-color-bg-brand);
  font-family: var(--ll-text-button-base-family);
  font-size: var(--ll-text-button-base-size);
  line-height: 20px;
  letter-spacing: var(--ll-text-button-base-letter-spacing);
  font-weight: var(--ll-text-button-base-weight);
}

@media (width >= 768px) {
  p.product-feature-tile__popup-cta {
    align-self: center;
    margin-block-start: calc(var(--ll-space-6) - var(--pft-popup-gap));
  }

  p.product-feature-tile__popup-cta > a.button {
    width: var(--ll-button-width, auto);
    height: auto;
    padding: var(--ll-space-5) var(--ll-space-7);
    font-family: var(--ll-text-button-lg-family);
    font-size: var(--ll-text-button-lg-size);
    line-height: var(--ll-text-button-lg-line-height);
    letter-spacing: var(--ll-text-button-lg-letter-spacing);
    font-weight: var(--ll-text-button-lg-weight);
  }
}

/* Pin the header + CTA (WEBEXP-110878): only the middle scroll region may
 * absorb the height squeeze, so kicker/title/CTA never shrink or clip when the
 * frame hits max-height. Declared last to satisfy descending-specificity. */
.pft-modal .product-feature-tile__popup-kicker,
.pft-modal .product-feature-tile__popup-title,
.pft-modal p.product-feature-tile__popup-cta {
  flex-shrink: 0;
}

/* --- Reduced motion -----------------------------------------------------
 *
 * When the user has requested reduced motion, keep the open/close behavior
 * (opening and closing still happen; the block would be unusable otherwise)
 * but collapse the visual to a short opacity-only fade and drop all
 * transforms. Same idiom the prototype uses (see product-feature-tiles.md
 * "Motion"). */
@media (prefers-reduced-motion: reduce) {
  .product-feature-tile,
  .pft-modal__backdrop,
  .pft-modal__frame {
    transition-duration: 0.15s !important;
    transition-property: opacity !important;
  }

  .product-feature-tile:hover {
    transform: none !important;
  }

  .pft-modal__frame {
    opacity: 0;
    transform: none !important;
  }

  .pft-modal--open .pft-modal__frame {
    opacity: 1;
    transform: none !important;
  }

  .pft-modal--closing .pft-modal__frame {
    opacity: 0;
    transform: none !important;
  }
}
