/* ============================================================
   /technology/face-recognition/ — Facial recognition (KEYTECH).
   Clones document-verification: the page root carries BOTH
   .p-document-verification (shared sheet applies) and
   .p-keytech-face-recognition (this sheet — additions/overrides only).
   Scoped .p-keytech-face-recognition. Tokens only.

   Round 2 (charter + regression fixes, 2026-08-01):
   - G10 · the card-hero is viewport-locked again. Copy LEFT / face-match
     result mock RIGHT, sized to its column — the card no longer grows past
     the viewport (the round-1 full-width band grew it).
   - G12 · the 5 tech cards are equalized: name reserves 2 lines, body
     reserves 2 lines, so every viz panel is byte-identical size.
   - G13 · one illustration style (the Workflow Builder canvas): white ground,
     grey skeleton faces, hairlines, one blue accent, green/red only as status.
     The red *striped* defense tile and the near-black "dim" env tile are gone;
     both normalized to clean light frames.
   - regression · the "Imagen (…)" title tooltip is removed from the DOM
     (the viz briefs live in the .astro const, greppable, not rendered).
   ============================================================ */

/* ---- built-mock frame + Mockup chip ---- */
.p-keytech-face-recognition .frx-mock {
  position: relative; width: 100%; aspect-ratio: var(--ph-ar, 16 / 9);
  overflow: hidden; border-radius: 16px; background: var(--color-white);
  box-shadow: inset 0 0 0 1px var(--color-border-light);
}
.p-keytech-face-recognition .frx-mock--dark {
  background:
    radial-gradient(120% 120% at 10% -20%, color-mix(in oklab, var(--color-blue-500) 40%, transparent), transparent 60%),
    color-mix(in oklab, var(--color-black) 84%, var(--color-blue-500));
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
}
.p-keytech-face-recognition .frx-mock__chip {
  position: absolute; top: 9px; right: 10px; z-index: 6;
  padding: 2px 8px; border-radius: 999px;
  background: var(--color-placeholder-yellow); color: var(--color-black);
  font-size: 11px; font-weight: 600; line-height: 1.45;
}

/* ---- canonical person glyph (G13 / ronda-3): the site's user icon masked
   into a clean circular avatar chip — no grey silhouette bust anymore. One
   glyph reused across every mock; recolour via --face-c. ---- */
.p-keytech-face-recognition .frx-face {
  position: relative; display: grid; place-items: center;
  height: 56%; aspect-ratio: 1; max-width: 100%; border-radius: 50%;
  background: var(--color-grey-100);
  box-shadow: inset 0 0 0 1px var(--color-border-light);
  --face-c: var(--color-grey-400);
}
.p-keytech-face-recognition .frx-face::before {
  content: ""; width: 72%; height: 72%; background: var(--face-c);
  -webkit-mask: url(/icons/user.svg) center / contain no-repeat;
          mask: url(/icons/user.svg) center / contain no-repeat;
}
.p-keytech-face-recognition .frx-face--muted { --face-c: var(--color-grey-300); background: var(--color-grey-50); }

.p-keytech-face-recognition .frx-scan {
  position: absolute; left: 14%; right: 14%; top: 44%; height: 2px; z-index: 2;
  background: linear-gradient(90deg, transparent, var(--color-blue-500), transparent);
  box-shadow: none;
  animation: frx-scan 2.8s var(--ease-out-expo) infinite;
}
@keyframes frx-scan {
  0% { top: 26%; opacity: 0; }
  14% { opacity: 1; }
  52% { top: 70%; opacity: 1; }
  66%, 100% { top: 70%; opacity: 0; }
}

.p-keytech-face-recognition .frx-tag {
  display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; z-index: 3;
  padding: 3px 8px; border-radius: 999px; font-size: 11px; font-weight: 600; line-height: 1.4;
  background: var(--color-white); color: var(--color-grey-500);
  box-shadow: inset 0 0 0 1px var(--color-border-light);
}
.p-keytech-face-recognition .frx-tag svg { width: 11px; height: 11px; }
.p-keytech-face-recognition .frx-tag--live,
.p-keytech-face-recognition .frx-tag--ok,
.p-keytech-face-recognition .frx-tag--bad {
  position: absolute; left: 50%; bottom: 8%; transform: translateX(-50%);
}
.p-keytech-face-recognition .frx-tag--ok { color: var(--color-green-600); }
.p-keytech-face-recognition .frx-tag--bad { color: var(--color-red-600); }
.p-keytech-face-recognition .frx-tag--info { color: var(--color-blue-500); align-self: flex-start; }

/* ============================================================
   1 · HERO — EXACT document-verification geometry (owner order
   2026-08-03): zero inner overrides, so the copy group (pill · title ·
   sub · actions) sits pixel-identical to /technology/document-verification/.
   The face-match window lives ONLY in the shared .dv-hero__foot band
   (the DV ID-row box).
   ============================================================ */
.p-keytech-face-recognition .frx-hero__copy { display: contents; }

/* the Face Capture phone, centered in the foot band. It TOP-docks
   (align-self: flex-start, against the band's flex-end default) and the
   band's bottom edge crops the lower screen — the phone rises out of
   the card foot. Geometry: the band is min(400px, 50svh) tall and the
   copy reserves clamp(220px, 32svh, 320px) above the card foot (the
   inner's bottom padding), so the phone's top margin is exactly the
   band's copy overlap + a 12px gap, and its width tracks svh so the
   ring AND caption (~62% down the 390×844 screen) stay above the cut. */
.p-keytech-face-recognition .frx-hero__media {
  align-self: flex-start;
  margin-top: calc(min(400px, 50svh) - clamp(220px, 32svh, 320px) + 12px);
  width: clamp(176px, 22svh, 232px);
  min-width: 0;
}

/* ---- the animated Face Capture PHONE (hero mock v3, 2026-08-05) ----
   Product screen = Selfie3Screen.astro (the customer-onboarding vector
   twin) inside the site's abstracted phone bezel (sol-stage__frame
   values). Figma refs: capture 2311-50193, uploading 2311-50181.
   State classes set by /js/behaviors/frx-capture.js on [data-frx-capture]:
   (rest = capturing) → .is-captured → .is-uploading → .is-done, with
   .is-busy/.is-ok per check row and .is-reset to suppress transitions
   while the loop rewinds. Overlay geometry derives from the screen's
   390×844 viewBox: ring cx195 cy313.5 outer-r167.5, camera r145.5. */
.p-keytech-face-recognition .frx-phone { position: relative; }
.p-keytech-face-recognition .frx-phone__frame {
  padding: 9px; border-radius: 42px;
  border: 1px solid var(--color-grey-100); background: var(--color-white);
  box-shadow: none;
}
.p-keytech-face-recognition .frx-phone__screen {
  position: relative; overflow: hidden; border-radius: 34px;
}
.p-keytech-face-recognition .frx-phone__svg { display: block; width: 100%; height: auto; }
/* the screen's own photo/scene circles, captions and silhouette hide —
   the live video + HTML captions replace them */
.p-keytech-face-recognition .frx-phone .s3-photo,
.p-keytech-face-recognition .frx-phone .s3-scene,
.p-keytech-face-recognition .frx-phone .s3-silhouette,
.p-keytech-face-recognition .frx-phone .s3-caption,
.p-keytech-face-recognition .frx-phone .s3-caption-ready { display: none; }
.p-keytech-face-recognition .frx-phone .s3-avatar { transition: opacity 0.35s ease; }
/* the spinning capture arc — the screen's own blue gradient ring
   (.s3-ring-scan), revealed and rotated about its center */
.p-keytech-face-recognition .frx-phone .s3-ring-scan {
  display: block; transform-box: fill-box; transform-origin: center;
  animation: frx-arc-spin 1.3s linear infinite;
  transition: opacity 0.35s ease;
}
@keyframes frx-arc-spin { to { transform: rotate(1turn); } }
.p-keytech-face-recognition .is-captured .s3-ring-scan { opacity: 0; }
/* circular camera feed + the head-outline silhouette, over the SVG's
   photo circle (cx195 cy313.5 r145.5 of 390×844) */
.p-keytech-face-recognition .frx-phone__cam {
  position: absolute; left: 12.692%; top: 19.905%;
  width: 74.615%; height: 34.479%;
  display: block; border-radius: 50%; overflow: hidden;
  background: var(--color-grey-50);
  transition: opacity 0.35s ease;
}
.p-keytech-face-recognition .frx-phone__cam video {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
/* Figma placement of the outline within the circle:
   inset(3.8% -24.79% -41.26% -24.35%) → width 149.14%, clipped by the circle */
.p-keytech-face-recognition .frx-phone__outline {
  position: absolute; left: -24.35%; top: 3.8%; width: 149.14%; max-width: none;
}
/* ring overlay box (the track's outer square: cx195 cy313.5 r167.5) —
   carries the green sweep and the check badge */
.p-keytech-face-recognition .frx-phone__ringbox {
  position: absolute; left: 7.051%; top: 17.299%;
  width: 85.897%; height: 39.692%;
  display: block; transition: opacity 0.35s ease;
}
/* the green sweep — draws around the track when capture lands */
.p-keytech-face-recognition .frx-phone__sweep {
  position: absolute; inset: 0; width: 100%; height: 100%;
  transform: rotate(-90deg);
}
.p-keytech-face-recognition .frx-phone__sweep circle {
  fill: none; stroke: var(--color-green-500); stroke-width: 9; stroke-linecap: round;
  stroke-dasharray: 100 100; stroke-dashoffset: 100;
  transition: stroke-dashoffset 0.7s var(--ease-out-expo);
}
.p-keytech-face-recognition .is-captured .frx-phone__sweep circle { stroke-dashoffset: 0; }
/* the check badge — pops on the ring once the sweep lands */
.p-keytech-face-recognition .frx-phone__badge {
  position: absolute; left: 50%; bottom: 2px; z-index: 2;
  width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  color: var(--color-white); background: var(--color-green-500);
  box-shadow: 0 0 0 3px var(--color-white);
  transform: translateX(-50%) scale(0);
  transition: transform 0.4s var(--ease-out-expo) 0.45s;
}
.p-keytech-face-recognition .frx-phone__badge svg { width: 15px; height: 15px; }
.p-keytech-face-recognition .is-captured .frx-phone__badge { transform: translateX(-50%) scale(1); }
/* captions — stacked states, one active (dv-swap-style). The capture
   caption sits under the ring (the screen's own caption slot); the
   uploading caption belongs to the upstage block. */
.p-keytech-face-recognition .frx-phone__caption {
  display: grid; text-align: center; margin: 0;
}
.p-keytech-face-recognition .frx-phone__caption--cap {
  position: absolute; left: 0; right: 0; top: 59.2%;
  transition: opacity 0.35s ease;
}
.p-keytech-face-recognition .frx-phone__cap {
  grid-area: 1 / 1; opacity: 0; transform: translateY(4px);
  font-family: var(--font-display); font-weight: 700; letter-spacing: var(--track-tight);
  font-size: 16px; color: var(--color-black);
  transition: opacity 0.3s ease, transform 0.3s ease;
}
.p-keytech-face-recognition .frx-phone__cap.is-active { opacity: 1; transform: none; }
/* capture stage hides while uploading */
.p-keytech-face-recognition .is-uploading .frx-phone__cam,
.p-keytech-face-recognition .is-uploading .frx-phone__ringbox,
.p-keytech-face-recognition .is-uploading .frx-phone__caption--cap,
.p-keytech-face-recognition .is-uploading .s3-avatar,
.p-keytech-face-recognition .is-uploading .s3-ring-scan { opacity: 0; }
/* ---- uploading stage (Figma 2311-50181): centered spinner + title ---- */
.p-keytech-face-recognition .frx-phone__upstage {
  position: absolute; left: 0; right: 0; top: 32%;
  display: grid; justify-items: center; gap: 14px;
  opacity: 0; transition: opacity 0.35s ease;
}
.p-keytech-face-recognition .is-uploading .frx-phone__upstage {
  opacity: 1; transition-delay: 0.2s;
}
.p-keytech-face-recognition .frx-phone__upslot { display: grid; place-items: center; }
.p-keytech-face-recognition .frx-phone__upslot > * { grid-area: 1 / 1; }
.p-keytech-face-recognition .frx-phone__spinner {
  width: 44px; height: 44px;
  animation: frx-arc-spin 0.9s linear infinite;
  transition: opacity 0.25s ease;
}
.p-keytech-face-recognition .frx-phone__spinner circle { fill: none; stroke-width: 5.5; }
.p-keytech-face-recognition .frx-phone__spinner-track { stroke: var(--color-blue-100); }
.p-keytech-face-recognition .frx-phone__spinner-arc {
  stroke: var(--color-blue-500); stroke-linecap: round;
  stroke-dasharray: 26 74;
}
/* done: the spinner swaps to the green check */
.p-keytech-face-recognition .frx-phone__upbadge {
  width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center;
  color: var(--color-white); background: var(--color-green-500);
  transform: scale(0);
  transition: transform 0.4s var(--ease-out-expo);
}
.p-keytech-face-recognition .frx-phone__upbadge svg { width: 19px; height: 19px; }
.p-keytech-face-recognition .is-done .frx-phone__spinner { opacity: 0; animation-play-state: paused; }
.p-keytech-face-recognition .is-done .frx-phone__upbadge { transform: scale(1); }
/* the floating background-checks card (uploading state) — overhangs the
   phone's right edge */
.p-keytech-face-recognition .frx-selfie__checks {
  position: absolute; top: 33%; left: calc(100% - 34px); z-index: 3;
  width: 208px; padding: 11px 13px 12px; border-radius: 12px;
  background: var(--color-white);
  box-shadow: inset 0 0 0 1px var(--color-border-light);
  opacity: 0; transform: translateY(10px);
  transition: opacity 0.4s ease, transform 0.4s var(--ease-out-expo);
}
.p-keytech-face-recognition .is-uploading .frx-selfie__checks { opacity: 1; transform: none; }
.p-keytech-face-recognition .frx-selfie__checks-title {
  display: block; margin-bottom: 8px;
  font-size: var(--fs-xs); font-weight: 600; color: var(--color-grey-400);
}
.p-keytech-face-recognition .frx-selfie__checklist {
  display: grid; gap: 7px; margin: 0; padding: 0; list-style: none;
}
.p-keytech-face-recognition .frx-selfie__checklist li {
  display: flex; align-items: center; gap: 7px; white-space: nowrap;
  font-size: 11px; font-weight: 600; color: var(--color-grey-500);
}
.p-keytech-face-recognition .frx-selfie__checklist em {
  margin-left: auto; font-style: normal; font-weight: 600;
  color: var(--color-green-600); opacity: 0; transition: opacity 0.3s ease;
}
.p-keytech-face-recognition .frx-selfie__checklist li.is-ok em { opacity: 1; }
.p-keytech-face-recognition .frx-selfie__dot {
  position: relative; flex: 0 0 auto; width: 13px; height: 13px; border-radius: 50%;
  border: 1.5px solid var(--color-grey-200);
  transition: background-color 0.25s ease, border-color 0.25s ease;
}
.p-keytech-face-recognition li.is-busy .frx-selfie__dot {
  border-color: var(--color-grey-100); border-top-color: var(--color-blue-500);
  animation: frx-dot-spin 0.7s linear infinite;
}
@keyframes frx-dot-spin { to { transform: rotate(1turn); } }
.p-keytech-face-recognition li.is-ok .frx-selfie__dot {
  border-color: var(--color-green-500); background: var(--color-green-500);
}
.p-keytech-face-recognition li.is-ok .frx-selfie__dot::before {
  content: ""; position: absolute; inset: 1px; background: var(--color-white);
  -webkit-mask: url(/icons/check.svg) center / contain no-repeat;
          mask: url(/icons/check.svg) center / contain no-repeat;
}
/* narrow screens — smaller phone, checks card stays on-viewport with
   names only, smaller captions */
@media (max-width: 560px) {
  .p-keytech-face-recognition .frx-hero__media { width: min(64vw, 240px); }
  .p-keytech-face-recognition .frx-phone__cap { font-size: 14px; }
  .p-keytech-face-recognition .frx-phone__badge { width: 26px; height: 26px; }
  .p-keytech-face-recognition .frx-phone__badge svg { width: 13px; height: 13px; }
  .p-keytech-face-recognition .frx-phone__spinner { width: 38px; height: 38px; }
  /* the card floats in the empty band above the spinner — beside the
     phone it would cover the caption, below it the fold clips it */
  .p-keytech-face-recognition .frx-selfie__checks { width: 148px; left: auto; right: -6px; top: 13%; }
  .p-keytech-face-recognition .frx-selfie__checklist em { display: none; }
}

/* loop rewind — kill every transition for one frame */
.p-keytech-face-recognition .is-reset .s3-ring-scan,
.p-keytech-face-recognition .is-reset .s3-avatar,
.p-keytech-face-recognition .is-reset .frx-phone__cam,
.p-keytech-face-recognition .is-reset .frx-phone__ringbox,
.p-keytech-face-recognition .is-reset .frx-phone__sweep circle,
.p-keytech-face-recognition .is-reset .frx-phone__badge,
.p-keytech-face-recognition .is-reset .frx-phone__cap,
.p-keytech-face-recognition .is-reset .frx-phone__caption--cap,
.p-keytech-face-recognition .is-reset .frx-phone__upstage,
.p-keytech-face-recognition .is-reset .frx-phone__spinner,
.p-keytech-face-recognition .is-reset .frx-phone__upbadge,
.p-keytech-face-recognition .is-reset .frx-selfie__checks,
.p-keytech-face-recognition .is-reset .frx-selfie__checklist em,
.p-keytech-face-recognition .is-reset .frx-selfie__dot { transition: none; }
@media (prefers-reduced-motion: reduce) {
  .p-keytech-face-recognition .frx-phone .s3-ring-scan,
  .p-keytech-face-recognition .frx-phone__spinner,
  .p-keytech-face-recognition li.is-busy .frx-selfie__dot { animation: none; }
}

/* ============================================================
   4 · THE TECHNOLOGY — SCROLL-PINNED STEP-WALK (2026-08-07).
   The old 5-card grid is now a walk: a sol-how__* rail (base styles in
   solution.css — the section is wrapped in a bare .p-solution scope, like
   How it works) + an at-how__* deck whose illustration swaps per step.
   The walk mechanic is ported from kyc-aml.css and RESCOPED to
   .p-keytech-face-recognition .frx-tech; the extra .frx-tech ancestor
   beats solution.css's .p-solution .sol-how__* defaults (solution.css
   loads AFTER this sheet). Driven by the SHARED section-walk.js
   ([data-ka-walk] / [data-at-step] / [data-at-screen]).
   Every illustration: white/grey ground, hairline borders, grey skeleton
   faces, ONE blue accent, green = pass / red = spoof blocked. Tokens only.
   ============================================================ */

/* -- rail: jump-free reveal. Each description opens to the SAME measured
   height (--at-reveal-h, set by section-walk.js) so the rail's total height
   holds still on step change. Overrides solution.css's 0fr→1fr grid trick. */
.p-keytech-face-recognition .frx-tech .sol-how__reveal {
  display: block;
  height: 0;
  overflow: hidden;
  transition: height 0.45s cubic-bezier(0.23, 1, 0.32, 1);
}
.p-keytech-face-recognition .frx-tech .sol-how__step.is-active .sol-how__reveal {
  height: var(--at-reveal-h, 56px);
}
.p-keytech-face-recognition .frx-tech .sol-how__line { padding-top: 10px; }

/* -- scroll-pin walk (wide + motion): the section grows tall and its inner
   content pins for the length of the walk (72svh of scroll per step + one
   viewport), so scroll SELECTS the step. Static fallback (narrow /
   reduced-motion): the section is normal height, the pin is not sticky. */
.p-keytech-face-recognition .frx-tech__pin { position: relative; }
.p-keytech-face-recognition .frx-tech.is-walk {
  height: calc(100svh + 72svh * var(--ka-steps, 5));
}
.p-keytech-face-recognition .frx-tech.is-walk .frx-tech__pin {
  position: sticky;
  top: 0;
  min-height: 100svh;
  display: flex;
  align-items: center;
}

/* -- active-step underline. Walk mode: the active bar tracks the in-band
   scroll fraction (--ka-scrub, per frame from section-walk.js), walked-past
   steps hold a full bar. Static mode: a timed fill matching auto-advance
   (sol-how-fill keyframes live in solution.css). */
.p-keytech-face-recognition .frx-tech.is-walk .sol-how__step.is-active .sol-how__fill {
  transform: scaleX(var(--ka-scrub, 0));
  transition: transform 0.18s linear;
}
.p-keytech-face-recognition .frx-tech.is-walk .sol-how__step.is-done .sol-how__fill {
  transform: scaleX(0); /* only the active step keeps its bar (Camila 2026-08-10, site-wide) */
  transition: transform 0.4s ease;
}
.p-keytech-face-recognition .frx-tech:not(.is-walk) .sol-how__step.is-active .sol-how__fill {
  animation: sol-how-fill var(--sol-hold, 6s) linear forwards;
}
@media (prefers-reduced-motion: reduce) {
  .p-keytech-face-recognition .frx-tech:not(.is-walk) .sol-how__step.is-active .sol-how__fill { animation: none; }
}

/* -- the deck — a constant-height slot the stage centers, with a card whose
   height morphs to the active screen (top edge holds still). Overrides the
   static at-how__deck width (In-the-dashboard card) WITHIN this section
   only, so that card is untouched. */
.p-keytech-face-recognition .frx-tech .at-how__slot {
  width: min(100%, 420px);
  height: var(--at-slot-h, auto);
}
.p-keytech-face-recognition .frx-tech .at-how__deck {
  width: 100%;
  height: var(--at-screen-h, auto);
  transition: height 0.45s cubic-bezier(0.23, 1, 0.32, 1);
}
.p-keytech-face-recognition .frx-tech .at-how__screen { pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
  .p-keytech-face-recognition .frx-tech .at-how__deck,
  .p-keytech-face-recognition .frx-tech .sol-how__reveal { transition: none; }
}

/* -- the deck-card head status chip (pushed right; tone carries the result).
   The extra .frx-tech ancestor lifts these over the .at-how__pill base
   (defined later in this sheet for the In-the-dashboard card, same specificity
   otherwise) so the tone bg/colour wins. */
.p-keytech-face-recognition .frx-tech .frx-viz__chip {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  letter-spacing: 0.01em;
}
.p-keytech-face-recognition .frx-tech .frx-viz__chip svg { width: 11px; height: 11px; }
.p-keytech-face-recognition .frx-tech .frx-viz__chip--ok {
  background: color-mix(in oklab, var(--color-green-500) 13%, transparent);
  color: var(--color-green-600);
}
.p-keytech-face-recognition .frx-tech .frx-viz__chip--bad {
  background: color-mix(in oklab, var(--color-red-500) 13%, transparent);
  color: var(--color-red-600);
}
.p-keytech-face-recognition .frx-tech .frx-viz__chip--info {
  background: color-mix(in oklab, var(--color-blue-500) 14%, transparent);
  color: var(--color-blue);
}

/* -- shared illustration frame (fills the card body below the head) -- */
.p-keytech-face-recognition .frx-viz__art {
  position: relative;
  flex: 1;
  min-height: 172px;
  border: 1px solid var(--color-border-light);
  border-radius: 12px;
  background: var(--color-grey-50);
  overflow: hidden;
}

/* -- 01 · demographic fairness (near-level bars per group + parity line) -- */
.p-keytech-face-recognition .frx-fair { padding: 30px 18px 14px; display: flex; }
.p-keytech-face-recognition .frx-fair__parity {
  position: absolute; left: 18px; right: 18px; top: 28px; height: 0;
  border-top: 1.5px dashed color-mix(in oklab, var(--color-blue-500) 55%, transparent);
}
.p-keytech-face-recognition .frx-fair__parity em {
  position: absolute; right: 0; top: -8px; padding: 0 4px;
  background: var(--color-grey-50);
  font-size: 9.5px; font-style: normal; font-weight: 600; color: var(--color-blue);
}
.p-keytech-face-recognition .frx-fair__plot { flex: 1; display: flex; align-items: flex-end; justify-content: space-between; gap: 14px; }
.p-keytech-face-recognition .frx-fair__group {
  flex: 1; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 8px;
}
.p-keytech-face-recognition .frx-fair__bars { flex: 1; min-height: 0; width: 100%; display: flex; align-items: flex-end; justify-content: center; gap: 6px; }
.p-keytech-face-recognition .frx-fair__bars i {
  width: 16px; height: var(--h, 90%); border-radius: 4px 4px 0 0;
  background: linear-gradient(180deg, var(--color-blue-200), var(--color-blue-500));
}
.p-keytech-face-recognition .frx-fair__group b { font-size: 10px; font-weight: 600; color: var(--color-grey-500); }

/* -- 02 · environmental adaptability (4 labelled condition tiles) -- */
.p-keytech-face-recognition .frx-env { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; gap: 10px; padding: 12px; }
.p-keytech-face-recognition .frx-env__tile {
  position: relative; overflow: hidden; border-radius: 10px; display: grid; place-items: center;
  background: var(--color-white); box-shadow: inset 0 0 0 1px var(--color-border-light);
}
.p-keytech-face-recognition .frx-env__tile .frx-face { height: 44%; }
.p-keytech-face-recognition .frx-env__tile--dim { background: var(--color-grey-100); }
.p-keytech-face-recognition .frx-env__tile--dim .frx-face { --face-c: var(--color-grey-300); }
.p-keytech-face-recognition .frx-env__tile--back { background: linear-gradient(180deg, var(--color-blue-100), var(--color-white)); }
.p-keytech-face-recognition .frx-env__tile--angle .frx-face { transform: rotate(-12deg); }
.p-keytech-face-recognition .frx-env__tile--out { background: linear-gradient(180deg, var(--color-blue-100), color-mix(in oklab, var(--color-blue-500) 10%, var(--color-white))); }
.p-keytech-face-recognition .frx-env__tile b {
  position: absolute; left: 8px; bottom: 6px;
  font-size: 9.5px; font-weight: 600; color: var(--color-grey-500);
}
.p-keytech-face-recognition .frx-ok {
  position: absolute; top: 6px; right: 6px; width: 17px; height: 17px; border-radius: 50%;
  display: grid; place-items: center; color: var(--color-white); background: var(--color-green-600);
}
.p-keytech-face-recognition .frx-ok svg { width: 10px; height: 10px; }

/* -- 03 · passive liveness (centered portrait + blue scan + green tag) -- */
.p-keytech-face-recognition .frx-live { display: grid; place-items: center; }
.p-keytech-face-recognition .frx-live .frx-face { height: 50%; }
.p-keytech-face-recognition .frx-live .frx-scan { left: 33%; right: 33%; top: 46%; }

/* -- 04 · deepfake & injection defense (muted face + red shield-x + tag) -- */
.p-keytech-face-recognition .frx-def {
  display: grid; place-items: center;
  border-color: color-mix(in oklab, var(--color-red-500) 22%, var(--color-border-light));
}
.p-keytech-face-recognition .frx-def .frx-face { height: 48%; }
.p-keytech-face-recognition .frx-def__badge {
  position: absolute; top: 40%; left: 50%; transform: translate(-50%, -50%);
  width: 42px; height: 42px; border-radius: 50%; display: grid; place-items: center;
  color: var(--color-white); background: var(--color-red-600);
  box-shadow: 0 0 0 6px color-mix(in oklab, var(--color-red-600) 18%, transparent);
}
.p-keytech-face-recognition .frx-def__badge svg { width: 22px; height: 22px; }

/* -- 05 · 1:1 and 1:N matching (verify row + search row + latency tag) -- */
.p-keytech-face-recognition .frx-mn { display: flex; flex-direction: column; justify-content: center; gap: 14px; padding: 18px; }
.p-keytech-face-recognition .frx-mn__row { display: flex; align-items: center; gap: 11px; }
.p-keytech-face-recognition .frx-mn__tag { flex: 0 0 auto; width: 26px; font-family: var(--font-display); font-weight: 600; font-size: var(--fs-sm); color: var(--color-blue-500); }
.p-keytech-face-recognition .frx-portrait {
  position: relative; overflow: hidden; flex: 0 0 auto; width: 36px; aspect-ratio: 1; border-radius: 9px;
  background: var(--color-white); display: grid; place-items: center; box-shadow: inset 0 0 0 1px var(--color-border-light);
}
.p-keytech-face-recognition .frx-portrait .frx-face { height: 76%; }
.p-keytech-face-recognition .frx-portrait--id { box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--color-blue-500) 35%, var(--color-border-light)); }
.p-keytech-face-recognition .frx-mn__op { display: grid; place-items: center; width: 22px; height: 22px; color: var(--color-grey-400); }
.p-keytech-face-recognition .frx-mn__op svg { width: 16px; height: 16px; }
.p-keytech-face-recognition .frx-mn__row:first-child .frx-mn__op { color: var(--color-green-600); }
.p-keytech-face-recognition .frx-mn__db { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; }
.p-keytech-face-recognition .frx-mn__db i { width: 12px; height: 12px; border-radius: 3px; background: var(--color-grey-200); }
.p-keytech-face-recognition .frx-mn__db i.is-hit { background: var(--color-blue-500); box-shadow: 0 0 0 2px color-mix(in oklab, var(--color-blue-500) 25%, transparent); }
.p-keytech-face-recognition .frx-mn .frx-tag--info { margin-top: 2px; }

/* ============================================================
   5 · NIST BENCHMARK — dv-deepsight repurposed. Big static rank ("#1")
   + the built FRTE comparison chart (v7) on dark: Incode vs nearest
   IDV provider (fact-bank multipliers only; lower is better).
   ============================================================ */
.p-keytech-face-recognition .frx-nist__big { line-height: 0.86; }
.p-keytech-face-recognition .frx-nist__chart {
  margin-top: clamp(40px, 6vw, 64px); padding-top: clamp(32px, 5vw, 48px);
  border-top: 1px solid color-mix(in oklab, var(--color-white) 12%, transparent);
}
.p-keytech-face-recognition .frx-nist__mock { padding: clamp(18px, 2.4vw, 32px) clamp(20px, 3vw, 40px); }

.p-keytech-face-recognition .frx-bench { display: flex; flex-direction: column; height: 100%; }
.p-keytech-face-recognition .frx-bench__head { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.p-keytech-face-recognition .frx-bench__ylabel { font-size: var(--fs-xs); color: rgba(255, 255, 255, 0.55); }
.p-keytech-face-recognition .frx-bench__legend { display: flex; gap: 16px; }
.p-keytech-face-recognition .frx-bench__key { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-xs); color: rgba(255, 255, 255, 0.72); }
.p-keytech-face-recognition .frx-bench__key::before { content: ""; width: 10px; height: 10px; border-radius: 3px; }
.p-keytech-face-recognition .frx-bench__key--rival::before { background: rgba(255, 255, 255, 0.28); }
.p-keytech-face-recognition .frx-bench__key--incode::before { background: var(--color-blue-500); }
.p-keytech-face-recognition .frx-bench__plot { flex: 1; min-height: 0; display: grid; grid-template-columns: 1fr 1fr; gap: clamp(24px, 6vw, 80px); align-items: end; padding-top: 22px; }
.p-keytech-face-recognition .frx-bench__group { display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 12px; height: 100%; }
.p-keytech-face-recognition .frx-bench__pair { flex: 1; min-height: 0; width: 100%; max-width: 260px; display: flex; align-items: flex-end; justify-content: center; gap: clamp(18px, 3vw, 44px); }
.p-keytech-face-recognition .frx-bench__bar { position: relative; width: clamp(40px, 6vw, 72px); height: var(--h, 100%); border-radius: 8px 8px 0 0; }
.p-keytech-face-recognition .frx-bench__bar--rival { background: linear-gradient(180deg, rgba(255, 255, 255, 0.34), rgba(255, 255, 255, 0.12)); }
.p-keytech-face-recognition .frx-bench__bar--incode {
  background: linear-gradient(180deg, var(--color-blue-200), var(--color-blue-500));
  box-shadow: none;
}
.p-keytech-face-recognition .frx-bench__glabel { font-size: var(--fs-xs); color: rgba(255, 255, 255, 0.66); text-align: center; }
.p-keytech-face-recognition .frx-bench__foot { margin-top: 14px; font-size: var(--fs-xs); color: rgba(255, 255, 255, 0.4); }

/* ============================================================
   Reduced motion
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .p-keytech-face-recognition .frx-scan { animation: none; top: 46%; }
}

/* ============================================================
   HOW IT WORKS — bespoke per-step stage (frxh-*, Camila 2026-08-06)
   The sol-how deck (solution.css) stacks the 5 scenes in one grid
   cell; solution-hero.js toggles .is-active per walked step. Each
   .frxh-card is a phone base + floating containers tied to its step.
   Base scaffold below; per-scene rules are appended per step.
   ============================================================ */
.p-solution .frxh-deck { place-items: center; }
.p-solution .frxh-card {
  position: relative;
  /* flex (not grid place-items) so the phone stays vertically centered in the
     card's extra min-height across ALL engines — grid align-content:normal
     resolves to stretch in Chrome but pins the row to the top elsewhere
     (Safari / some Chrome builds), which floated the phone high in the frame. */
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: min(60svh, 620px);
}
/* .sol-stage__screen (solution.css, loaded later) forces display:block +
   aspect-ratio, which top/left-aligns the phone. This ONE rule restores true
   centering for EVERY scene (0,3,0 beats solution.css's 0,2,0), so all five
   phone mockups sit in the exact same spot — dead center — and every scene's
   floating cards (which anchor to card-center) line up with the phone. It also
   holds on resize: place-items:center recentres at any width. Supersedes the
   old per-scene detect/vectorize overrides. */
.p-solution .sol-stage__screen.frxh-card {
  display: grid;
  place-items: center;
}
/* the shared phone base — abstracted bezel (sol-stage__frame values) */
.p-solution .frxh-phone {
  position: relative;
  width: clamp(184px, 15vw, 228px);
}
.p-solution .frxh-phone__frame {
  padding: 9px;
  border-radius: 42px;
  border: 1px solid var(--color-grey-100);
  background: var(--color-white);
}
.p-solution .frxh-phone__screen {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 390 / 844;
  object-fit: cover;
  object-position: center;
  border-radius: 34px;
  overflow: hidden;
}
/* detect renders the real Selfie3 screen (vector twin) instead of the jpg,
   so its own capture ring can spin — the svg fills the 390:844 box exactly,
   leaving the screen perfectly centered in the bezel (no crop). */
.p-solution .frxh-phone__svg {
  display: block;
  width: 100%;
  height: auto;
}
/* Reveal the stage in float mode. solution.css keeps .sol-how__stage at
   opacity:0 until .is-how-near, but solution-hero.js only sets that class
   when a TRAVELING phone exists — this walk is standalone (no traveler), so
   without this the visuals never appear on desktop. Scoped to .frxh-flow so
   it never touches the shared component or other pages; the extra
   .p-keytech-face-recognition + .p-solution ancestors give it the
   specificity to win over solution.css, which loads AFTER this sheet. */
.p-keytech-face-recognition .p-solution .frxh-flow.is-float .sol-how__stage {
  opacity: 1;
  transform: translateY(24px);
}

/* Only the ACTIVE step carries the blue underline. The shared sol-how walk
   (solution.css) keeps a full blue bar on every walked-past step as a
   wayfinding trail, but on this page Camila wants passed steps to fall back
   to the plain grey hairline — so a done step's fill recedes to scaleX(0)
   (the existing 0.4s transition eases the blue out). Scoped to .frxh-flow
   with the .p-keytech-face-recognition + .p-solution ancestors so it wins
   over solution.css (loaded later) WITHOUT changing the trail on kyc-aml or
   any other solution page. */
.p-keytech-face-recognition .p-solution .frxh-flow.is-float .sol-how__step.is-done .sol-how__fill {
  transform: scaleX(0);
}

/* ---- per-scene rules (assembled from .context/frxh/) ---- */
/* FRXH-SCENE-CSS-ANCHOR */

/* ---- scene 01 · detect ---- */
/* ============================================================
   frxh scene 01 · DETECT
   "Isolates and analyzes the face in an image or video, often
    within milliseconds." — the real Face Capture screen (the
   Selfie3 vector twin) with its OWN blue capture ring spinning,
   exactly like the page hero. No fake tracking box overlay; a green
   chip confirms the lock with a latency stat.
   Every selector is scoped to .p-solution .frxh-card--detect.
   The spin reuses the frx-arc-spin keyframe (defined above).
   ============================================================ */

/* the screen's own capture ring (.s3-ring-scan) — revealed and rotated
   about its center, matching the hero's Face Capture phone. solution.css
   hides it by default (.p-solution .s3-ring-scan); this 4-class selector
   wins on specificity. It spins continuously; once a face is detected its
   gradient shifts blue → green and it KEEPS spinning green (see motion). */
.p-solution .frxh-card--detect .frxh-phone__svg .s3-ring-scan {
  display: block;
  transform-box: fill-box;
  transform-origin: center;
}

/* Center the phone mockup in the visual container. The shared
   .sol-stage__screen rule (solution.css, loaded later) forces
   display:block, which top-aligns the phone while the chip overlay is
   already card-centered. Centering is now handled once for all scenes by the
   shared `.sol-stage__screen.frxh-card` rule in the base scaffold above. */

/* Chip overlay root — sized to the phone SCREEN footprint (phone width
   minus the 9px pad + 1px border on each side) and centered over the
   centered phone, so the chip maps to true screen %. */
.p-solution .frxh-card--detect .frxh-detect {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: calc(clamp(184px, 15vw, 228px) - 20px);
  aspect-ratio: 390 / 844;
  z-index: 3;
  pointer-events: none;
}

/* ---- confirmation chip — overhangs the phone's right edge ---- */
.p-solution .frxh-card--detect .frxh-detect__chip {
  position: absolute;
  top: 30%;
  left: calc(100% - 26px);
  display: flex;
  align-items: center;
  gap: 9px;
  width: max-content;
  padding: 9px 13px;
  border-radius: 12px;
  background: var(--color-white);
  box-shadow: inset 0 0 0 1px var(--color-border-light);
}
.p-solution .frxh-card--detect .frxh-detect__chip-icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  color: var(--color-white);
  background: var(--color-green-500);
}
.p-solution .frxh-card--detect .frxh-detect__chip-icon svg {
  width: 12px;
  height: 12px;
}
.p-solution .frxh-card--detect .frxh-detect__chip-text {
  display: flex;
  flex-direction: column;
  line-height: 1;
}
.p-solution .frxh-card--detect .frxh-detect__chip-label {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--color-grey-400);
  margin-bottom: 3px;
}
.p-solution .frxh-card--detect .frxh-detect__chip-stat {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  color: var(--color-green-600);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

/* ============================================================
   Motion — the ring spins continuously; when a face is detected it
   turns green and KEEPS spinning (no fade). The "Face detected · 24 ms"
   chip only appears at that green moment. Gated on .frxh-flow.is-float
   (the section is in view, IntersectionObserver-driven) so the blue →
   green beat starts when the visual reveals, not off-screen at load.
   Timeline (once the section is in view + detect is the active step):
     0.0–1.8s  ring spins BLUE (capturing)
     1.8–2.2s  gradient shifts blue → green (face detected)
     2.0s      the "Face detected" chip fades in
     2.2s →    ring keeps spinning GREEN, indefinitely
   At rest / under reduced motion: static blue ring, caption visible,
   chip hidden.
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {
  /* continuous spin, the whole time the step is live */
  .p-solution .frxh-flow.is-float .frxh-card--detect.is-active .frxh-phone__svg .s3-ring-scan {
    animation: frx-arc-spin 1.3s linear infinite;
  }
  /* one-shot blue → green in the ring's own gradient stop; holds green */
  .p-solution .frxh-flow.is-float .frxh-card--detect.is-active .frxh-phone__svg .s3-scan-stop {
    animation: frxh-cap-green 0.5s linear 1.8s both;
  }
  /* the chip appears at the green moment (not while still capturing) */
  .p-solution .frxh-card--detect .frxh-detect__chip {
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 0.45s ease, transform 0.5s var(--ease-out-expo);
  }
  .p-solution .frxh-flow.is-float .frxh-card--detect.is-active .frxh-detect__chip {
    opacity: 1;
    transform: translateY(0);
    transition-delay: 2s;
  }
}

@keyframes frxh-cap-green {
  from { stop-color: var(--color-blue-500); }
  to   { stop-color: var(--color-green-500); }
}

/* ---- scene 02 · extract ---- */
/* ============================================================
   scene 02 · Extract — the capture hands off to the "Uploading" UI
   (the SAME screen as the hero: the product screen blanks to its
   chrome, a centered spinner + caption take over) while a compact
   readout shows the CHARACTERISTICS being pulled. Deliberately
   generic — categories, not invented measurements — and calm: one
   blue accent, tokens only, no blue mesh overlay. Screen stays
   centered in the bezel; the readout is the only overhang.
   Every selector is scoped to .p-solution .frxh-card--extract.
   ============================================================ */

/* blank the selfie screen down to its chrome — the uploading state
   shows no face, just the product frame behind the spinner (mirrors
   the hero's .is-uploading treatment) */
.p-solution .frxh-card--extract .s3-avatar,
.p-solution .frxh-card--extract .s3-silhouette,
.p-solution .frxh-card--extract .s3-caption,
.p-solution .frxh-card--extract .s3-caption-ready {
  display: none;
}

/* overlay root — sized to the phone SCREEN (phone width − 20px frame
   inset) and centered over the centered phone, so its children map to
   true screen %. */
.p-solution .frxh-card--extract .frxh-x {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: calc(clamp(184px, 15vw, 228px) - 20px);
  aspect-ratio: 390 / 844;
  pointer-events: none;
  z-index: 3;
}

/* ---- uploading stage: centered spinner + caption ---- */
.p-solution .frxh-card--extract .frxh-x-upstage {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  display: grid;
  justify-items: center;
  gap: 12px;
}
.p-solution .frxh-card--extract .frxh-x-spinner {
  width: 40px;
  height: 40px;
}
.p-solution .frxh-card--extract .frxh-x-spinner circle {
  fill: none;
  stroke-width: 5.5;
}
.p-solution .frxh-card--extract .frxh-x-spinner-track {
  stroke: var(--color-blue-100);
}
.p-solution .frxh-card--extract .frxh-x-spinner-arc {
  stroke: var(--color-blue-500);
  stroke-linecap: round;
  stroke-dasharray: 26 74;
}
.p-solution .frxh-card--extract .frxh-x-uplabel {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: var(--track-tight);
  font-size: 15px;
  color: var(--color-black);
}

/* ---- floating readout — the characteristics being pulled (card
   language shared with the detect chip: white, radius-12, inset
   hairline; overhangs the phone's right edge) ---- */
.p-solution .frxh-card--extract .frxh-x-card {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  left: calc(100% - 32px);
  z-index: 4;
  margin: 0;
  width: 164px;
  padding: 12px 14px 13px;
  border-radius: 12px;
  background: var(--color-white);
  box-shadow: inset 0 0 0 1px var(--color-border-light);
}
.p-solution .frxh-card--extract .frxh-x-card__title {
  display: block;
  margin-bottom: 10px;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--color-grey-400);
}
.p-solution .frxh-card--extract .frxh-x-list {
  display: grid;
  gap: 9px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.p-solution .frxh-card--extract .frxh-x-list li {
  display: flex;
  align-items: center;
  gap: 9px;
  white-space: nowrap;
}
.p-solution .frxh-card--extract .frxh-x-tick {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  color: var(--color-blue-500);
  background: var(--color-blue-100);
}
.p-solution .frxh-card--extract .frxh-x-tick svg {
  width: 10px;
  height: 10px;
}
.p-solution .frxh-card--extract .frxh-x-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--color-grey-600);
}

/* ---- motion: gentle composed reveal keyed off the active step.
   Resting/inactive state already reads correctly (full opacity). ---- */
@media (prefers-reduced-motion: no-preference) {
  /* the arc spins while the step is walked (the "uploading" feel) */
  .p-solution .frxh-card--extract.is-active .frxh-x-spinner {
    animation: frx-arc-spin 0.9s linear infinite;
  }

  /* card eases up when the step becomes active (keeps the -50% centering) */
  .p-solution .frxh-card--extract .frxh-x-card {
    opacity: 0;
    transform: translate(0, calc(-50% + 8px));
    transition: opacity 0.45s ease, transform 0.45s var(--ease-out-expo);
  }
  .p-solution .frxh-card--extract.is-active .frxh-x-card {
    opacity: 1;
    transform: translateY(-50%);
    transition-delay: 0.18s;
  }

  /* the characteristic rows tick in one by one */
  .p-solution .frxh-card--extract .frxh-x-list li {
    opacity: 0;
    transform: translateY(4px);
    transition: opacity 0.4s ease, transform 0.4s var(--ease-out-expo);
  }
  .p-solution .frxh-card--extract.is-active .frxh-x-list li {
    opacity: 1;
    transform: none;
  }
  .p-solution .frxh-card--extract.is-active .frxh-x-list li:nth-child(1) { transition-delay: 0.30s; }
  .p-solution .frxh-card--extract.is-active .frxh-x-list li:nth-child(2) { transition-delay: 0.40s; }
  .p-solution .frxh-card--extract.is-active .frxh-x-list li:nth-child(3) { transition-delay: 0.50s; }
}

/* ---- scene 03 · vectorize ---- */
/* ============================================================
   scene 03 · VECTORIZE — the person's selfie, now vectorized.
   Reuses the real capture screen (Selfie3Screen, same as detect/extract),
   but the face PHOTO inside the circle is hidden and replaced by a dense
   grid of 1s and 0s — the numeric facial signature — clipped to that same
   circle so it reads as "this face → data". Dim grey bits, a few blue-500
   "hot" bits. Bits generated build-time in the page frontmatter (seeded →
   deterministic). Circle geometry mirrors the SVG: cx 195 / cy 313.5 /
   r 145.5 in the 390×844 screen (= 50% / 37.14% / 74.6% width). Scoped to
   .frxh-card--vectorize; keyframes prefixed frxh-vectorize-.
   ============================================================ */

/* keep the phone + chrome (status bar, wordmark, grey ring, verified footer)
   for context; drop only the layers that show the face photo / capture UI */
.p-solution .frxh-card--vectorize .s3-photo,
.p-solution .frxh-card--vectorize .s3-scene,
.p-solution .frxh-card--vectorize .s3-silhouette,
.p-solution .frxh-card--vectorize .s3-caption,
.p-solution .frxh-card--vectorize .s3-caption-ready,
.p-solution .frxh-card--vectorize .s3-ring-scan { display: none; }


.p-solution .frxh-card--vectorize .frxh-vec__screen { position: relative; }

/* subtle backdrop behind the numbers — a soft blue-tinted disc so the
   signature sits on something (not bare white), slightly larger than the
   number field so it peeks out inside the grey ring */
.p-solution .frxh-card--vectorize .frxh-vec__screen::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 37.14%;
  transform: translate(-50%, -50%);
  width: 79%;
  aspect-ratio: 1;
  z-index: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 42%,
    color-mix(in oklab, var(--color-blue-100) 60%, var(--color-white)) 0%,
    color-mix(in oklab, var(--color-blue-100) 22%, var(--color-white)) 55%,
    var(--color-grey-50) 100%);
}

/* the binary field, clipped to the capture circle */
.p-solution .frxh-card--vectorize .frxh-vec__disc {
  position: absolute;
  left: 50%;
  top: 37.14%;
  transform: translate(-50%, -50%);
  width: 74.6%;
  aspect-ratio: 1;
  z-index: 2;
  display: grid;
  grid-template-columns: repeat(13, 1fr);
  align-content: center;
  row-gap: 1.5%;
  overflow: hidden;
  border-radius: 50%;
  /* fade the digits toward the circle edge so they dissolve, not hard-clip */
  -webkit-mask-image: radial-gradient(circle at 50% 50%, #000 44%, rgba(0, 0, 0, 0.4) 76%, transparent 96%);
          mask-image: radial-gradient(circle at 50% 50%, #000 44%, rgba(0, 0, 0, 0.4) 76%, transparent 96%);
}
/* softened so the numbers read as a quiet texture, not in-your-face */
.p-solution .frxh-card--vectorize .frxh-vec__cell {
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  font-size: 8.5px;
  line-height: 1;
  text-align: center;
  color: var(--color-grey-300);
  opacity: 0.5;
}
.p-solution .frxh-card--vectorize .frxh-vec__cell--hot {
  color: var(--color-blue-500);
  opacity: 0.8;
}

/* active reveal — the signature fills in row-by-row, then the hot bits
   breathe. Resting state (and reduced-motion) = a fully-composed field. */
@media (prefers-reduced-motion: no-preference) {
  .p-solution .frxh-card--vectorize.is-active .frxh-vec__cell {
    animation: frxh-vectorize-in 0.5s var(--ease-out-expo) var(--vt, 0s) backwards;
  }
  .p-solution .frxh-card--vectorize.is-active .frxh-vec__cell--hot {
    animation: frxh-vectorize-in 0.5s var(--ease-out-expo) var(--vt, 0s) backwards,
               frxh-vectorize-pulse 2.6s ease-in-out calc(var(--vt, 0s) + 0.6s) infinite;
  }
}
@keyframes frxh-vectorize-in {
  from { opacity: 0; transform: translateY(3px) scale(0.9); }
  to   { opacity: 1; transform: none; }
}
@keyframes frxh-vectorize-pulse {
  0%, 100% { opacity: 0.45; }
  50%      { opacity: 0.75; }
}

@media (max-width: 560px) {
  .p-solution .frxh-card--vectorize .frxh-vec__cell { font-size: 7.5px; }
}

/* ---- scene 04 · encrypt ---- */
/* ============================================================
   scene 04 · Encrypt — "Seals the vector into a format only the right
   decryption key can open."
   Story: opens on the phone selfie (shared base); the captured face
   condenses into the dashboard avatar (one shared circular element), then
   the session is encrypted so only the necessary result stays disclosed.
   Restraint: cipher rows are neutral grey, blue is only the lock, green
   only the result; one sanctioned hard float shadow on the dashboard.
   Every selector is scoped to .p-solution .frxh-card--encrypt.
   Base (no-motion) state = the sealed dashboard result.
   ============================================================ */

/* layout knobs (also drive the morph landing; overridden ≤560px) */
.p-solution .frxh-card--encrypt {
  --enc-dash-w: 280px;   /* dashboard width */
  --enc-ava-x: -107px;   /* avatar centre X relative to the card centre */
  --enc-ava-y: -78px;    /* avatar centre Y relative to the card centre */
}

/* positioning context — the injected floats overlay the phone base */
.p-solution .frxh-card--encrypt .frxh-enc { position: absolute; inset: 0; }

/* the phone base is the opening frame; sealed base state hides it */
.p-solution .frxh-card--encrypt .frxh-phone { z-index: 1; opacity: 0; }

/* A · the dashboard "session" page — centred, one hard float shadow */
.p-solution .frxh-card--encrypt .frxh-enc__dash {
  position: absolute;
  left: 50%;
  top: calc(50% - 150px);
  transform: translateX(-50%);
  z-index: 2;
  width: var(--enc-dash-w);
  background: var(--color-white);
  border-radius: 16px;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px var(--color-border-light);
}

/* browser-chrome bar */
.p-solution .frxh-card--encrypt .frxh-enc__bar {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 40px;
  padding: 0 14px;
  border-bottom: 1px solid var(--color-border-light);
  background: var(--color-grey-50);
}
.p-solution .frxh-card--encrypt .frxh-enc__dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--color-grey-200);
}
.p-solution .frxh-card--encrypt .frxh-enc__crumb {
  margin-left: 8px; height: 6px; width: 78px; border-radius: 3px;
  background: var(--color-grey-200);
}
.p-solution .frxh-card--encrypt .frxh-enc__sess {
  margin-left: auto;
  font-family: var(--font-display);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0;
  text-transform: uppercase;
  color: var(--color-grey-400);
  background: var(--color-white);
  padding: 3px 9px;
  border-radius: 999px;
  box-shadow: inset 0 0 0 1px var(--color-border-light);
}

/* identity row — the empty avatar ring the travelling selfie lands on */
.p-solution .frxh-card--encrypt .frxh-enc__id {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 14px 16px 12px;
  border-bottom: 1px solid var(--color-border-light);
}
.p-solution .frxh-card--encrypt .frxh-enc__ava {
  width: 34px; height: 34px; flex: 0 0 auto;
  border-radius: 50%; overflow: hidden;
  background: var(--color-grey-100);
  box-shadow: inset 0 0 0 1px var(--color-border-light);
}
.p-solution .frxh-card--encrypt .frxh-enc__who {
  display: flex; flex-direction: column; gap: 6px; flex: 1;
}
.p-solution .frxh-card--encrypt .frxh-enc__who i {
  display: block; height: 6px; border-radius: 3px;
  background: var(--color-grey-200);
}
.p-solution .frxh-card--encrypt .frxh-enc__wn { width: 58%; background: var(--color-grey-300); }
.p-solution .frxh-card--encrypt .frxh-enc__ws { width: 38%; }

/* data rows — abstract line-text (plain) that folds into cipher */
.p-solution .frxh-card--encrypt .frxh-enc__rows {
  padding: 14px 16px 8px;
  display: flex; flex-direction: column; gap: 13px;
}
.p-solution .frxh-card--encrypt .frxh-enc__field { position: relative; }
.p-solution .frxh-card--encrypt .frxh-enc__plain {
  display: flex; flex-direction: column; gap: 6px;
}
.p-solution .frxh-card--encrypt .frxh-enc__label {
  height: 5px; width: 34%; border-radius: 3px;
  background: var(--color-grey-300);
}
.p-solution .frxh-card--encrypt .frxh-enc__val {
  display: flex; flex-direction: column; gap: 5px;
}
.p-solution .frxh-card--encrypt .frxh-enc__val i {
  display: block; height: 6px; border-radius: 3px;
  background: var(--color-grey-100);
}
/* the sealed cipher — neutral grey (no colour), overlays the plain rows */
.p-solution .frxh-card--encrypt .frxh-enc__cipher {
  position: absolute; inset: 0;
  display: flex; align-items: center;
}
.p-solution .frxh-card--encrypt .frxh-enc__cipher span {
  flex: 1;
  font-family: var(--font-display);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0;
  color: var(--color-grey-400);
  background: var(--color-grey-50);
  border-radius: 6px;
  padding: 6px 8px;
  line-height: 1.5;
  box-shadow: inset 0 0 0 1px var(--color-border-light);
  word-break: break-all;
}

/* the necessary result — the only thing left disclosed (green) */
.p-solution .frxh-card--encrypt .frxh-enc__result {
  margin: 6px 16px 16px;
  display: flex; align-items: center; gap: 10px;
  padding: 11px 13px;
  border-radius: var(--radius-md);
  background: var(--color-green-100);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--color-green-600) 22%, transparent);
}
.p-solution .frxh-card--encrypt .frxh-enc__check {
  width: 22px; height: 22px; flex: 0 0 auto;
  border-radius: 50%;
  background: var(--color-green-600);
  color: var(--color-white);
  display: grid; place-items: center;
}
.p-solution .frxh-card--encrypt .frxh-enc__check svg { width: 13px; height: 13px; }
.p-solution .frxh-card--encrypt .frxh-enc__rtxt {
  display: flex; flex-direction: column; gap: 5px; flex: 1;
}
.p-solution .frxh-card--encrypt .frxh-enc__rtxt i {
  display: block; height: 5px; border-radius: 3px;
  background: color-mix(in oklab, var(--color-green-600) 42%, var(--color-white));
}
.p-solution .frxh-card--encrypt .frxh-enc__ok {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 700;
  color: var(--color-green-600);
  letter-spacing: 0;
  white-space: nowrap;
}

/* B · the single lock — the one blue accent; clicks to seal */
.p-solution .frxh-card--encrypt .frxh-enc__lock {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  z-index: 7;
  width: 38px; height: 38px;
  border-radius: 50%;
  display: grid; place-items: center;
  color: var(--color-white);
  background: var(--color-blue-500);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--color-blue-500) 70%, transparent);
}
.p-solution .frxh-card--encrypt .frxh-enc__lock svg { width: 20px; height: 20px; }

/* C · the travelling selfie — the shared element: phone face → avatar.
   Zoomed (210%) so the FACE fills the circle; blurred for privacy.
   Base transform rests it exactly on the dashboard avatar. */
.p-solution .frxh-card--encrypt .frxh-enc__face {
  position: absolute; left: 50%; top: 50%; z-index: 6;
  width: 34px; height: 34px;
  margin: -17px 0 0 -17px;
  border-radius: 50%; overflow: hidden;
  transform-origin: center;
  background: url(/product-snapshots/core/face-capture/selfie-3.jpg) 50% 30% / 210% no-repeat;
  box-shadow: inset 0 0 0 1px var(--color-border-light);
  filter: blur(1.4px);
  transform: translate(var(--enc-ava-x), var(--enc-ava-y));
}

/* ---- base (no-motion / reduced-motion): sealed dashboard shown ---- */
.p-solution .frxh-card--encrypt .frxh-enc__plain { opacity: 0; }
.p-solution .frxh-card--encrypt .frxh-enc__cipher { opacity: 1; }
.p-solution .frxh-card--encrypt .frxh-enc__lock { opacity: 0; }

/* ---- entrance · keyed off the active step. selfie → face condenses into
   the avatar → session seals → only the result stays disclosed. ---- */
@media (prefers-reduced-motion: no-preference) {
  /* RESTING state = the SEALED dashboard (inherited from the base rules
     above), NOT the opening frame. This is deliberate: when the step is
     walked AWAY from (4 → 5), the card only loses .is-active, so its
     resting look is what shows during the deck's cross-fade out. Holding
     the sealed dashboard here means encrypt simply fades out as-is —
     no reverse-snap back to the phone screen before the transition
     (Camila 2026-08-06). The OPENING frame is not lost on entry: each
     .is-active animation below carries its own 0% (opening) keyframe and
     fills backwards (`both`), so the phone-selfie → seal sequence still
     plays from the top every time the step is entered. The one value a
     0% can't reconstruct is the plaintext staying visible through the
     pre-fold hold — frxh-enc-hide gains an explicit `from:1` for that. */

  /* ON ACTIVE: play */
  .p-solution .frxh-card--encrypt.is-active .frxh-phone {
    animation: frxh-enc-phone-out 0.28s ease 1s both;
  }
  .p-solution .frxh-card--encrypt.is-active .frxh-enc__face {
    animation: frxh-enc-travel 1.6s var(--ease-out-expo) 1s both;
  }
  .p-solution .frxh-card--encrypt.is-active .frxh-enc__dash {
    animation: frxh-enc-dash-in 0.65s var(--ease-out-expo) 1.15s both;
  }
  .p-solution .frxh-card--encrypt.is-active .frxh-enc__lock {
    animation: frxh-enc-lock 1.1s var(--ease-out-expo) 2.75s both;
  }
  .p-solution .frxh-card--encrypt.is-active .frxh-enc__field--1 .frxh-enc__plain { animation: frxh-enc-hide 0.01s linear 3.05s both; }
  .p-solution .frxh-card--encrypt.is-active .frxh-enc__field--1 .frxh-enc__cipher { animation: frxh-enc-fold 0.5s var(--ease-out-expo) 3.05s both; }
  .p-solution .frxh-card--encrypt.is-active .frxh-enc__field--2 .frxh-enc__plain { animation: frxh-enc-hide 0.01s linear 3.25s both; }
  .p-solution .frxh-card--encrypt.is-active .frxh-enc__field--2 .frxh-enc__cipher { animation: frxh-enc-fold 0.5s var(--ease-out-expo) 3.25s both; }
  .p-solution .frxh-card--encrypt.is-active .frxh-enc__field--3 .frxh-enc__plain { animation: frxh-enc-hide 0.01s linear 3.45s both; }
  .p-solution .frxh-card--encrypt.is-active .frxh-enc__field--3 .frxh-enc__cipher { animation: frxh-enc-fold 0.5s var(--ease-out-expo) 3.45s both; }
  .p-solution .frxh-card--encrypt.is-active .frxh-enc__result {
    animation: frxh-enc-result 0.55s var(--ease-out-expo) 4s both;
  }
}

@keyframes frxh-enc-phone-out {
  0% { opacity: 1; }
  100% { opacity: 0; transform: scale(1.03); }
}
@keyframes frxh-enc-travel {
  0% { transform: translate(0, -58px) scale(3.4); opacity: 0; }
  10% { opacity: 1; }
  100% { transform: translate(var(--enc-ava-x), var(--enc-ava-y)); opacity: 1; }
}
@keyframes frxh-enc-dash-in {
  0% { opacity: 0; transform: translateX(-50%) scale(0.96); }
  100% { opacity: 1; transform: translateX(-50%); }
}
@keyframes frxh-enc-lock {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(0.4); }
  45% { opacity: 1; transform: translate(-50%, -50%) scale(1.12); }
  68% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(1); }
}
@keyframes frxh-enc-hide { from { opacity: 1; } to { opacity: 0; } }
@keyframes frxh-enc-fold {
  0% { opacity: 0; transform: translateY(-6px) scaleY(0.7); }
  100% { opacity: 1; transform: none; }
}
@keyframes frxh-enc-result {
  0% { opacity: 0; transform: translateY(6px); }
  100% { opacity: 1; transform: none; }
}

/* narrow screens — a slimmer dashboard; morph landing follows via vars */
@media (max-width: 560px) {
  .p-solution .frxh-card--encrypt {
    --enc-dash-w: 240px;
    --enc-ava-x: -87px;
  }
}

/* ---- scene 05 · compare ---- */
/* ============================================================
   scene 05 · Compare — the sealed signature matched to the real
   person. Renders the shared FaceMatch1Screen ("Verifying identity"),
   the SAME visual as the kyc-aml how-it-works "Match the person" step,
   and replays that step's motion when the step is walked: the Selfie
   and ID portraits glide toward each other while the "Selfie" / "ID"
   tags fade out just before they meet. Values mirror solution.css's
   co-fm-* (the traveling-phone version) so the motion matches kyc-aml
   exactly; keyframes are re-declared + prefixed here so this standalone
   walk owns its own timing and doesn't depend on the co-* trigger
   (which keys off svg[data-sol-screen="2"], absent in this deck).
   Motion only under prefers-reduced-motion: no-preference.
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {
  /* the two portraits slide toward each other (±25px in the 390-wide
     screen's user space), keyed to the step becoming active */
  .p-solution .frxh-card--compare.is-active .fm-face-selfie {
    animation: frxh-compare-selfie-in 1.5s cubic-bezier(0.85, 0, 0.25, 1) 0.3s both;
  }
  .p-solution .frxh-card--compare.is-active .fm-face-id {
    animation: frxh-compare-id-in 1.5s cubic-bezier(0.85, 0, 0.25, 1) 0.3s both;
  }
  /* the Selfie / ID bubble tags fade out just before the faces meet */
  .p-solution .frxh-card--compare.is-active .fm-tag-selfie,
  .p-solution .frxh-card--compare.is-active .fm-tag-id {
    animation: frxh-compare-tag-out 0.4s ease 1.2s both;
  }
}
@keyframes frxh-compare-selfie-in {
  from { transform: translateX(0); }
  to { transform: translateX(25px); }
}
@keyframes frxh-compare-id-in {
  from { transform: translateX(0); }
  to { transform: translateX(-25px); }
}
@keyframes frxh-compare-tag-out {
  from { opacity: 1; }
  to { opacity: 0; }
}

/* NOTE: the .frxh-compare__* rules below are legacy — they styled the old
   1:1/1:N floating cards, whose markup was removed when this step adopted
   the FaceMatch1Screen. Kept dormant (they match nothing now) pending a
   dead-CSS sweep. */

/* shared float chrome for both cards. --half tracks the phone's half-width
   so the cards overhang the phone edges regardless of the (wider) card cell. */
.p-solution .frxh-card--compare {
  --frxh-compare-half: clamp(92px, 7.5vw, 114px);
}
.p-solution .frxh-card--compare .frxh-compare__card {
  position: absolute;
  z-index: 3;
  width: 156px;
  padding: 11px 13px 12px;
  border-radius: 12px;
  background: var(--color-white);
  box-shadow: inset 0 0 0 1px var(--color-border-light);
  display: flex;
  flex-direction: column;
}

/* 1:1 verify — overhangs the LEFT edge, near the phone top */
.p-solution .frxh-card--compare .frxh-compare__verify {
  top: 13%;
  right: calc(50% + var(--frxh-compare-half) - 40px);
}
/* 1:N search — overhangs the RIGHT edge, near the phone bottom */
.p-solution .frxh-card--compare .frxh-compare__search {
  bottom: 12%;
  left: calc(50% + var(--frxh-compare-half) - 40px);
}

/* small label (matches .frx-selfie__checks-title) */
.p-solution .frxh-card--compare .frxh-compare__label {
  display: block;
  margin-bottom: 10px;
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--color-grey-400);
}

/* ---- 1:1 verify card ---- */
.p-solution .frxh-card--compare .frxh-compare__pair {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.p-solution .frxh-card--compare .frxh-compare__cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
}
.p-solution .frxh-card--compare .frxh-compare__cell em {
  font-style: normal;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--color-grey-400);
}
/* the ID photo reads as a card (wider than the square selfie chip) */
.p-solution .frxh-card--compare .frxh-compare__idcard {
  width: 44px;
  aspect-ratio: 1.32;
}
/* green "verified equals" between the two faces */
.p-solution .frxh-card--compare .frxh-compare__op {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  color: var(--color-white);
  background: var(--color-green-500);
  box-shadow: 0 0 0 5px color-mix(in oklab, var(--color-green-500) 18%, transparent);
}
.p-solution .frxh-card--compare .frxh-compare__op svg { width: 13px; height: 13px; }
/* the match-score chip */
.p-solution .frxh-card--compare .frxh-compare__score {
  align-self: flex-start;
  margin-top: 11px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 9px;
  border-radius: 999px;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-xs);
  color: var(--color-green-600);
  background: color-mix(in oklab, var(--color-green-500) 12%, var(--color-white));
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--color-green-500) 30%, transparent);
}
.p-solution .frxh-card--compare .frxh-compare__score svg { width: 12px; height: 12px; }

/* ---- 1:N search card ---- */
.p-solution .frxh-card--compare .frxh-compare__db {
  display: grid;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.p-solution .frxh-card--compare .frxh-compare__db li {
  display: flex;
  align-items: center;
  gap: 8px;
}
/* smaller face chips for the database rows */
.p-solution .frxh-card--compare .frxh-compare__db .frx-portrait {
  width: 22px;
  border-radius: 6px;
}
/* the per-row match bar (grey fill = low confidence) */
.p-solution .frxh-card--compare .frxh-compare__bar {
  position: relative;
  flex: 1;
  height: 6px;
  border-radius: 3px;
  background: var(--color-grey-100);
  overflow: hidden;
}
.p-solution .frxh-card--compare .frxh-compare__bar::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--w, 40%);
  border-radius: 3px;
  background: var(--color-grey-300);
}
/* the hit row — green portrait, full green bar, green check */
.p-solution .frxh-card--compare .frxh-compare__db .is-hit .frx-portrait {
  background: color-mix(in oklab, var(--color-green-500) 10%, var(--color-white));
  box-shadow: inset 0 0 0 1.5px var(--color-green-500);
}
.p-solution .frxh-card--compare .frxh-compare__db .is-hit .frx-face {
  background: transparent;
  box-shadow: none;
  --face-c: var(--color-green-600);
}
.p-solution .frxh-card--compare .frxh-compare__db .is-hit .frxh-compare__bar {
  background: color-mix(in oklab, var(--color-green-500) 16%, var(--color-white));
}
.p-solution .frxh-card--compare .frxh-compare__db .is-hit .frxh-compare__bar::before {
  background: var(--color-green-500);
}
.p-solution .frxh-card--compare .frxh-compare__hit {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  color: var(--color-white);
  background: var(--color-green-500);
}
.p-solution .frxh-card--compare .frxh-compare__hit svg { width: 10px; height: 10px; }
/* footnote (matches the small blue-info language on this page) */
.p-solution .frxh-card--compare .frxh-compare__found {
  margin-top: 10px;
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--color-blue-500);
}

/* ---- entrance · composed at rest, subtle lift on the active step ----
   Resting state is fully visible (the deck cross-fades cards), so the scene
   reads correctly with zero motion. Under motion, inactive cards sit a touch
   low/soft and settle when the step is walked. */
@media (prefers-reduced-motion: no-preference) {
  .p-solution .frxh-card--compare .frxh-compare__card {
    opacity: 0.82;
    transform: translateY(8px);
    transition: opacity 0.5s ease, transform 0.5s var(--ease-out-expo);
  }
  .p-solution .frxh-card--compare.is-active .frxh-compare__verify {
    opacity: 1;
    transform: none;
    transition-delay: 0.05s;
  }
  .p-solution .frxh-card--compare.is-active .frxh-compare__search {
    opacity: 1;
    transform: none;
    transition-delay: 0.16s;
  }
  /* the hit row pulses its ring once the step is active */
  .p-solution .frxh-card--compare.is-active .frxh-compare__db .is-hit .frx-portrait {
    animation: frxh-compare-hit 2.4s var(--ease-out-expo) infinite;
  }
}
@keyframes frxh-compare-hit {
  0%, 100% { box-shadow: inset 0 0 0 1.5px var(--color-green-500), 0 0 0 0 color-mix(in oklab, var(--color-green-500) 40%, transparent); }
  40% { box-shadow: inset 0 0 0 1.5px var(--color-green-500), 0 0 0 4px color-mix(in oklab, var(--color-green-500) 0%, transparent); }
}

/* narrow screens — smaller cards, pulled in so they stay on-viewport */
@media (max-width: 560px) {
  .p-solution .frxh-card--compare .frxh-compare__card { width: 132px; padding: 9px 11px 10px; }
  .p-solution .frxh-card--compare .frxh-compare__verify { right: calc(50% + var(--frxh-compare-half) - 30px); }
  .p-solution .frxh-card--compare .frxh-compare__search { left: calc(50% + var(--frxh-compare-half) - 30px); }
}

/* ============================================================
   4b · IN THE DASHBOARD — the Single Session face-recognition RESULT
   (frx-ss), now a SECOND SCROLL-PINNED STEP-WALK (converted 2026-08-07).
   Same mechanic as the frx-tech walk above (a sol-how__* rail — base styles
   from solution.css, the section wrapped in a bare .p-solution scope — plus
   an at-how__* deck that swaps the result card per step). The walk mechanic
   is RESCOPED to .p-keytech-face-recognition .frx-ss so it never touches the
   frx-tech walk. Driven by the SHARED section-walk.js ([data-ka-walk] /
   [data-at-step] / [data-at-screen]) — one include drives both walks. The
   at-how / kam dashboard-card kit below stays shared with frx-tech; labels
   are grounded in the real ms-incode Single Session face surface (see the
   .astro comment). Tokens only.
   ============================================================ */

/* -- rail: jump-free reveal (mirrors frx-tech). Each description opens to the
   same measured height (--at-reveal-h, set by section-walk.js) so the rail's
   total height holds still on step change. Overrides solution.css's 0fr→1fr
   grid trick. */
.p-keytech-face-recognition .frx-ss .sol-how__reveal {
  display: block;
  height: 0;
  overflow: hidden;
  transition: height 0.45s cubic-bezier(0.23, 1, 0.32, 1);
}
.p-keytech-face-recognition .frx-ss .sol-how__step.is-active .sol-how__reveal {
  height: var(--at-reveal-h, 56px);
}
.p-keytech-face-recognition .frx-ss .sol-how__line { padding-top: 10px; }

/* -- scroll-pin walk (wide + motion): the section grows tall and its inner
   content pins for the length of the walk. Static fallback (narrow /
   reduced-motion): normal height, pin not sticky. */
.p-keytech-face-recognition .frx-ss__pin { position: relative; }
.p-keytech-face-recognition .frx-ss.is-walk {
  height: calc(100svh + 72svh * var(--ka-steps, 3));
}
.p-keytech-face-recognition .frx-ss.is-walk .frx-ss__pin {
  position: sticky;
  top: 0;
  min-height: 100svh;
  display: flex;
  align-items: center;
}

/* -- active-step underline. Walk mode: the active bar tracks the in-band
   scroll fraction (--ka-scrub); walked-past steps hold a full bar. Static
   mode: a timed fill matching auto-advance (keyframes in solution.css). */
.p-keytech-face-recognition .frx-ss.is-walk .sol-how__step.is-active .sol-how__fill {
  transform: scaleX(var(--ka-scrub, 0));
  transition: transform 0.18s linear;
}
.p-keytech-face-recognition .frx-ss.is-walk .sol-how__step.is-done .sol-how__fill {
  transform: scaleX(0); /* only the active step keeps its bar (Camila 2026-08-10, site-wide) */
  transition: transform 0.4s ease;
}
.p-keytech-face-recognition .frx-ss:not(.is-walk) .sol-how__step.is-active .sol-how__fill {
  animation: sol-how-fill var(--sol-hold, 6s) linear forwards;
}
@media (prefers-reduced-motion: reduce) {
  .p-keytech-face-recognition .frx-ss:not(.is-walk) .sol-how__step.is-active .sol-how__fill { animation: none; }
}

/* -- stage widen (this walk only): give the deck more room so the in-window
   dashboard (nav + face + result rows) can breathe, mirroring Liveness. Scoped
   to .frx-ss so the frx-tech walk above keeps the shared column balance. */
@media (min-width: 1024px) {
  .p-keytech-face-recognition .frx-ss .sol-how__inner {
    grid-template-columns: minmax(0, 0.74fr) minmax(0, 1.26fr);
    gap: 56px;
  }
}

/* ============================================================
   frd-* — the Single Session dashboard framed in a light browser window
   (chrome → grey-line nav → header PASS pill + Session ID → round selfie
   avatar beside the per-step result rows). Ported from the Liveness lvw-*
   template and page-scoped to .p-keytech-face-recognition; the chrome/nav/
   head/face frame is persistent while the [data-at-screen] result cards
   crossfade with the walk. Tokens only.
   ============================================================ */
.p-keytech-face-recognition .frd-deck {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(100%, 640px);
  margin-inline: auto;
  border-radius: 14px;
  border: 1px solid var(--color-border-light);
  background: var(--color-white);
  box-shadow: none;
  overflow: hidden;
}
/* Browser chrome is now the shared <BrowserChrome /> component (brchrome-*,
   components/browser-chrome.css) — the bespoke .frd-chrome* CSS was removed. */
/* the dashboard inside the window: de-emphasised nav + main */
.p-keytech-face-recognition .frd-app {
  display: flex;
  align-items: stretch;
  min-height: 300px;
}
.p-keytech-face-recognition .frd-appnav {
  flex-shrink: 0;
  width: 120px;
  display: flex;
  flex-direction: column;
  gap: 15px;
  padding: 18px 12px;
  background: var(--color-grey-50);
  border-right: 1px solid var(--color-grey-100);
}
.p-keytech-face-recognition .frd-appnav__line {
  height: 7px; border-radius: 999px; background: var(--color-grey-200);
}
.p-keytech-face-recognition .frd-appmain {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column;
}
.p-keytech-face-recognition .frd-apphead {
  display: flex; align-items: center; gap: 10px;
  height: 44px; padding: 0 20px;
  border-bottom: 1px solid var(--color-grey-100);
  flex-shrink: 0;
}
.p-keytech-face-recognition .frd-apphead__pass {
  padding: 4px 12px; border-radius: 999px;
  background: var(--color-green-100); color: var(--color-green-600);
  font-size: 12px; font-weight: 600;
}
.p-keytech-face-recognition .frd-apphead__sid {
  font-size: 12px; font-weight: 500; color: var(--color-grey-400);
}
.p-keytech-face-recognition .frd-body {
  display: flex;
  align-items: stretch;
  flex: 1;
  min-width: 0;
}
/* persistent round selfie avatar (left) — the same capture loop as the hero */
.p-keytech-face-recognition .frd-face {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
  padding: 18px 20px;
  border-right: 1px solid var(--color-grey-100);
}
.p-keytech-face-recognition .frd-face__cap {
  position: relative;
  width: 150px;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  overflow: hidden;
  background: var(--color-blue-100);
  border: 1px solid var(--color-grey-100);
}
.p-keytech-face-recognition .frd-face__cam {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
/* crossfaded result cards (right) */
.p-keytech-face-recognition .frd-screens {
  position: relative;
  display: grid;
  flex: 1;
  min-width: 0;
  align-self: stretch;
}
.p-keytech-face-recognition .frd-screen {
  grid-area: 1 / 1;
  align-self: start;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 236px;
  padding: 18px 20px;
  opacity: 0;
  transition: opacity 0.2s ease;
  pointer-events: none;
}
.p-keytech-face-recognition .frd-screen.is-active {
  opacity: 1;
  transition: opacity 0.35s ease 0.05s;
}
.p-keytech-face-recognition .frd-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--color-grey-on-white);
}
.p-keytech-face-recognition .frd-head .ds-icon { width: 18px; height: 18px; color: var(--color-grey-400); }

/* result rows (label · pill), hairline separators, no boxes */
.p-keytech-face-recognition .frd-table { display: flex; flex-direction: column; }
.p-keytech-face-recognition .frd-trow {
  display: grid;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--color-border-light);
}
.p-keytech-face-recognition .frd-trow:last-child { border-bottom: 0; }
.p-keytech-face-recognition .frd-trow--split { grid-template-columns: minmax(0, 1fr) auto; }
.p-keytech-face-recognition .frd-trow__lbl { font-size: 12px; font-weight: 500; color: var(--color-grey-500); }

/* tone pills — green for a passing value, red for a negative one */
.p-keytech-face-recognition .frd-pill {
  white-space: nowrap;
  justify-self: end;
  font-size: 10px;
  font-weight: 600;
  line-height: 1.5;
  padding: 3px 9px;
  border-radius: 999px;
}
.p-keytech-face-recognition .frd-pill--good { background: var(--color-green-100); color: var(--color-green-600); }
.p-keytech-face-recognition .frd-pill--bad { background: var(--color-red-100); color: var(--color-red-600); }

/* footer chips (accent chip + neutral chip) */
.p-keytech-face-recognition .frd-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: auto;
}
.p-keytech-face-recognition .frd-chip {
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--color-grey-100);
  color: var(--color-grey-on-white);
  font-size: var(--fs-xs);
  font-weight: 600;
}
.p-keytech-face-recognition .frd-chip--accent {
  background: color-mix(in oklab, var(--color-blue-500) 14%, transparent);
  color: var(--color-blue);
}

/* choreography — pills pop each time a step activates */
.p-keytech-face-recognition .frd-screen .frd-pill { opacity: 0; transform: translateY(3px) scale(0.9); }
.p-keytech-face-recognition .frd-screen.is-active .frd-pill {
  animation: frd-pop 0.45s cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: var(--d, 0s);
}
@keyframes frd-pop {
  from { opacity: 0; transform: translateY(3px) scale(0.9); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .p-keytech-face-recognition .frx-ss .sol-how__reveal { transition: none; }
  .p-keytech-face-recognition .frd-screen { transition: none; }
  .p-keytech-face-recognition .frd-screen .frd-pill { animation: none !important; opacity: 1; transform: none; }
}

/* ---- at-how deck kit — SHARED with the frx-tech walk above (do not remove) ---- */
.p-keytech-face-recognition .at-how__deck {
  position: relative;
  display: grid;
  width: min(100%, 420px);
  overflow: hidden;
  border-radius: 16px;
  border: 1px solid var(--color-border-light);
  background: var(--color-white);
  box-shadow: none;
}
.p-keytech-face-recognition .at-how__screen {
  grid-area: 1 / 1;
  align-self: start;
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-height: 232px;
  padding: 22px;
  opacity: 0;
  transition: opacity 0.2s ease;
}
.p-keytech-face-recognition .at-how__screen.is-active {
  opacity: 1;
  transition: opacity 0.35s ease 0.05s;
}

/* screen chrome */
.p-keytech-face-recognition .at-how__head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--color-grey-on-white);
}
.p-keytech-face-recognition .at-how__head .ds-icon {
  width: 18px;
  height: 18px;
  color: var(--color-grey-400);
}
.p-keytech-face-recognition .at-how__pill {
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--color-grey-100);
  color: var(--color-grey-on-white);
  font-size: var(--fs-xs);
  font-weight: 600;
  white-space: nowrap;
}
/* (frx-ss-only at-how rules — pill--accent, frx-ss__status, at-how__row,
   at-how__lane*, at-how__audit* — were replaced by the frd-* browser-window
   kit above and removed.) */

@media (prefers-reduced-motion: reduce) {
  .p-keytech-face-recognition .at-how__screen { transition: none; }
}

