/* ============================================================
   /technology/reusable-identity/ — Key Technologies category page.
   Additions + overrides ONLY; the base template lives in
   /styles/pages/document-verification.css and loads first. Everything
   here is scoped .p-keytech-reusable-identity. Tokens only.

   ROUND 2 (2026-07-31, storytelling fixer): the 7 yellow §2a
   placeholder tiles were replaced with BUILT wireframe mockups —
   white screens, light-grey skeleton shapes, thin hairlines, one
   blue accent — so Nacim sees the intended final art. Each mock
   keeps its data-ph (greppable) + a discreet 11px "Mockup" corner
   chip. Surface: hybrid (end-user phone screens · privacy diagram ·
   one dashboard step-up view).
   ============================================================ */

/* ---- mockup wrapper + discreet "Mockup" identifier chip ---- */
.p-keytech-reusable-identity .ri-mock { position: relative; width: 100%; }
.p-keytech-reusable-identity .ri-mock__chip {
  position: absolute; top: 8px; right: 8px; z-index: 6;
  padding: 2px 7px; border-radius: 999px;
  background: var(--color-placeholder-yellow); color: var(--color-black);
  font-size: 11px; font-weight: 600; line-height: 1.45; letter-spacing: var(--track-wide);
  pointer-events: none;
}

/* ---- wireframe skeleton primitives ---- */
.p-keytech-reusable-identity .ri-line { width: var(--w, 100%); height: var(--h, 7px); border-radius: 4px; background: var(--color-grey-100); flex: 0 0 auto; }
.p-keytech-reusable-identity .ri-line--2 { background: var(--color-grey-200); }
.p-keytech-reusable-identity .ri-line--accent { background: color-mix(in oklab, var(--color-blue-200) 82%, var(--color-white)); }
.p-keytech-reusable-identity .ri-row { display: flex; align-items: center; gap: 8px; }
.p-keytech-reusable-identity .ri-row--between { justify-content: space-between; }
.p-keytech-reusable-identity .ri-stack { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.p-keytech-reusable-identity .ri-strike { position: relative; }
.p-keytech-reusable-identity .ri-strike::after { content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: var(--color-grey-300); }

/* icons inside mocks are masked SVGs — color comes from the parent */
.p-keytech-reusable-identity .ri-check { width: 18px; height: 18px; border-radius: 50%; background: var(--color-green-flow); display: grid; place-items: center; color: var(--color-white); flex: 0 0 auto; }
.p-keytech-reusable-identity .ri-check .ds-icon { width: 11px; height: 11px; }

.p-keytech-reusable-identity .ri-toggle { position: relative; width: 30px; height: 18px; border-radius: 999px; background: var(--color-grey-200); flex: 0 0 auto; }
.p-keytech-reusable-identity .ri-toggle::after { content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: var(--color-white); box-shadow: none; }
.p-keytech-reusable-identity .ri-toggle--on { background: var(--color-blue-500); }
.p-keytech-reusable-identity .ri-toggle--on::after { left: auto; right: 2px; }

.p-keytech-reusable-identity .ri-btn { width: var(--w, auto); height: 26px; border-radius: 999px; background: var(--color-blue-500); flex: 0 0 auto; }
.p-keytech-reusable-identity .ri-btn--ghost { background: transparent; box-shadow: inset 0 0 0 1px var(--color-grey-200); }
.p-keytech-reusable-identity .ri-btn--wide { align-self: stretch; }
.p-keytech-reusable-identity .ri-btn-row { display: grid; grid-template-columns: 1.5fr 1fr; gap: 8px; align-self: stretch; }

.p-keytech-reusable-identity .ri-face { width: 66px; height: 66px; border-radius: 50%; border: 2px solid var(--color-blue-500); display: grid; place-items: center; color: var(--color-grey-300); background: color-mix(in oklab, var(--color-blue-100) 55%, var(--color-white)); flex: 0 0 auto; }
.p-keytech-reusable-identity .ri-face .ds-icon { width: 34px; height: 34px; }
.p-keytech-reusable-identity .ri-face--sm { width: 54px; height: 54px; border-width: 1.5px; }
.p-keytech-reusable-identity .ri-face--sm .ds-icon { width: 27px; height: 27px; }

.p-keytech-reusable-identity .ri-chip-ok { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px 4px 4px; border-radius: 999px; background: color-mix(in oklab, var(--color-green-flow) 12%, var(--color-white)); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--color-green-flow) 26%, transparent); }

/* ---- device frames ---- */
.p-keytech-reusable-identity .ri-phone { width: 100%; max-width: var(--ri-phone-w, 180px); aspect-ratio: 195 / 300; padding: 6px; border-radius: 20px; background: var(--color-white); box-shadow: inset 0 0 0 1px var(--color-grey-200); }
.p-keytech-reusable-identity .ri-phone__screen { height: 100%; border-radius: 15px; overflow: hidden; background: var(--color-white); box-shadow: inset 0 0 0 1px var(--color-grey-100); display: flex; flex-direction: column; gap: 9px; padding: 13px 11px; }

.p-keytech-reusable-identity .ri-win { width: 100%; border-radius: 12px; overflow: hidden; background: var(--color-white); box-shadow: inset 0 0 0 1px var(--color-grey-200); display: flex; flex-direction: column; }
.p-keytech-reusable-identity .ri-win__bar { display: flex; align-items: center; gap: 6px; padding: 8px 11px; background: var(--color-grey-50); box-shadow: inset 0 -1px 0 var(--color-grey-100); }
.p-keytech-reusable-identity .ri-win__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--color-grey-200); flex: 0 0 auto; }
.p-keytech-reusable-identity .ri-win__bar .ri-line { margin-left: 6px; }
.p-keytech-reusable-identity .ri-win__body { flex: 1; padding: 14px; display: flex; flex-direction: column; gap: 10px; }

/* ============================================================
   1 · HERO — clean copy hero. The paired phone/console composite
   that rode the card foot was REMOVED (owner order 2026-08-07), so
   the .dv-hero__foot band no longer renders. The base template
   reserves a tall bottom padding for that foot visual; with it gone
   we rebalance the copy group to sit vertically centered on the
   aurora (symmetric top/bottom padding), consistent with a standard
   left-aligned copy hero. Tokens only.
   ============================================================ */
.p-keytech-reusable-identity .ri-hero__copy { display: contents; }

/* rebalance: match bottom padding to the top so the copy centers in the
   full-height hero (the base template's tall foot-reserve padding is no
   longer needed without the removed foot visual). */
.p-keytech-reusable-identity .dv-hero__inner { padding-bottom: 132px; }
@media (min-width: 1024px) {
  .p-keytech-reusable-identity .dv-hero__inner { padding-bottom: clamp(120px, 15svh, 168px); }
}

/* ============================================================
   Operator dashboard mock + match meter — the light console window
   that lived behind the hero phone was removed with the hero visual.
   Only .ri-meter survives (still referenced by the review-console
   score row below); the .ri-dash* / .ri-avatar* / .ri-tag* skeleton
   rules that ONLY dressed the removed hero mock are gone.
   ============================================================ */
.p-keytech-reusable-identity .ri-meter { flex: 1; height: 8px; border-radius: 999px; background: var(--color-grey-100); overflow: hidden; }
.p-keytech-reusable-identity .ri-meter i { display: block; height: 100%; width: var(--f, 90%); border-radius: 999px; background: linear-gradient(90deg, var(--color-blue-200), var(--color-blue-500)); }

/* face scan sweep — subtle, ambient (disabled under reduced motion) */
.p-keytech-reusable-identity .ri-face { position: relative; overflow: hidden; }
.p-keytech-reusable-identity .ri-face__sweep {
  position: absolute; left: 0; right: 0; top: 0; height: 42%;
  background: linear-gradient(180deg, color-mix(in oklab, var(--color-blue-500) 22%, transparent), transparent);
  animation: ri-sweep 2.8s var(--ease-out-expo) infinite;
}
@keyframes ri-sweep {
  0% { transform: translateY(-30%); opacity: 0; }
  15% { opacity: 1; }
  80% { transform: translateY(200%); opacity: 1; }
  100% { transform: translateY(200%); opacity: 0; }
}

/* ============================================================
   3b · DUAL — user phone ↔ operator console, tied by the token.
   Light section. Dashboard is 16:9 (G11); phone is a tall device.
   ============================================================ */
.p-keytech-reusable-identity .ri-dual { background: var(--color-white); border-top: 1px solid var(--color-border-light); }
.p-keytech-reusable-identity .ri-dual__head { max-width: 640px; }
.p-keytech-reusable-identity .ri-dual__head .dv-intro { margin-top: 14px; }
.p-keytech-reusable-identity .ri-dual__stage {
  margin-top: clamp(36px, 5vw, 56px);
  display: grid; gap: 28px; align-items: start;
}
@media (min-width: 900px) {
  .p-keytech-reusable-identity .ri-dual__stage {
    grid-template-columns: minmax(0, 0.82fr) auto minmax(0, 1.12fr);
    gap: clamp(16px, 2.4vw, 34px);
  }
}
.p-keytech-reusable-identity .ri-dual__side { margin: 0; min-width: 0; }
.p-keytech-reusable-identity .ri-dual__cap { display: flex; align-items: center; gap: 11px; margin: 0 0 18px; }
.p-keytech-reusable-identity .ri-dual__cap-ic {
  width: 36px; height: 36px; border-radius: 9px; flex: 0 0 auto;
  display: grid; place-items: center;
  background: var(--color-grey-100); color: var(--color-grey-500);
}
.p-keytech-reusable-identity .ri-dual__cap-ic--blue { background: var(--color-blue-100); color: var(--color-blue-500); }
.p-keytech-reusable-identity .ri-dual__cap-ic .ds-icon { width: 18px; height: 18px; }
.p-keytech-reusable-identity .ri-dual__cap-txt { display: flex; flex-direction: column; font-size: var(--fs-sm); color: var(--color-grey-on-white); line-height: 1.35; }
.p-keytech-reusable-identity .ri-dual__cap-txt b { font-family: var(--font-display); font-weight: 500; font-size: var(--fs-body); color: var(--color-black); }
.p-keytech-reusable-identity .ri-dual__phonewrap { display: grid; place-items: center; }
.p-keytech-reusable-identity .ri-phone--tall { max-width: 234px; aspect-ratio: 200 / 424; margin-inline: auto; }

/* connector — a token traveling from the user's tap to the console.
   Figures top-align (captions line up, G12/RONDA-3 alignment); the link
   self-centers on the row so the token still lands at mid-height. */
.p-keytech-reusable-identity .ri-dual__link { position: relative; display: grid; place-items: center; min-height: 44px; align-self: center; }
.p-keytech-reusable-identity .ri-dual__link-line { position: absolute; left: 0; right: 0; top: 50%; height: 2px; transform: translateY(-50%); background: linear-gradient(90deg, var(--color-grey-200), var(--color-blue-200)); }
.p-keytech-reusable-identity .ri-dual__link-badge {
  position: relative; z-index: 1; width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center; background: var(--color-white); color: var(--color-blue-500);
  box-shadow: inset 0 0 0 1px var(--color-grey-100);
}
.p-keytech-reusable-identity .ri-dual__link-badge .ds-icon { width: 20px; height: 20px; }
.p-keytech-reusable-identity .ri-dual__link-pulse {
  position: absolute; top: 50%; left: 0; width: 8px; height: 8px; margin-top: -4px; border-radius: 50%;
  background: var(--color-blue-500); box-shadow: 0 0 0 4px color-mix(in oklab, var(--color-blue-500) 20%, transparent);
  animation: ri-travel 2.6s var(--ease-out-expo) infinite;
}
@keyframes ri-travel { 0% { left: 2%; opacity: 0; } 12% { opacity: 1; } 82% { left: 90%; opacity: 1; } 100% { left: 90%; opacity: 0; } }
@media (max-width: 899px) {
  .p-keytech-reusable-identity .ri-dual__link-line { left: 50%; right: auto; top: 0; bottom: 0; width: 2px; height: auto; transform: translateX(-50%); background: linear-gradient(180deg, var(--color-grey-200), var(--color-blue-200)); }
  .p-keytech-reusable-identity .ri-dual__link-pulse { display: none; }
}

/* ============================================================
   v2–v6 · the returning-user experience cards. The template's
   blue capture panel is overridden to a light panel so the built
   mocks read as intentional screens (not busy blue scenery).
   ============================================================ */
.p-keytech-reusable-identity .dv-cap__viz {
  background: var(--color-grey-50);
  box-shadow: inset 0 1px 0 var(--color-border-light);
  padding: 0;
  /* one fixed stage height (not flex-grown) so the five panels measure
     identical regardless of copy length above them (G12). 320px suits
     the round-4 Figma compositions: card 01's 200px live capture circle
     centers with 60px clearance, and every floating sub-card keeps
     ≥14px inset from the panel edge */
  flex: 0 0 auto;
  min-height: 0;
  height: 320px;
}
/* the mock fills the panel so the element + chip position against it */
.p-keytech-reusable-identity .dv-cap__viz .ri-mock { position: absolute; inset: 0; }

/* selfie screen (v2) */
.p-keytech-reusable-identity .ri-screen--selfie { align-items: center; justify-content: space-between; text-align: center; padding-block: 15px; }
.p-keytech-reusable-identity .ri-screen--selfie .ri-stack { align-items: center; }

/* skip-the-document screen (v3) — content clusters at top, action pinned
   to the bottom so the frame fills with the same vertical rhythm as the
   selfie / step-up siblings (G12 read-consistency) */
.p-keytech-reusable-identity .ri-screen--doc { justify-content: space-between; }
.p-keytech-reusable-identity .ri-doc-top { display: flex; flex-direction: column; gap: 9px; }
.p-keytech-reusable-identity .ri-doc-card { display: flex; align-items: center; gap: 9px; padding: 9px; border-radius: 10px; background: var(--color-grey-50); box-shadow: inset 0 0 0 1px var(--color-grey-100); }
.p-keytech-reusable-identity .ri-doc-card .ri-stack { flex: 1; }
.p-keytech-reusable-identity .ri-doc-thumb { width: 34px; height: 26px; border-radius: 5px; background: color-mix(in oklab, var(--color-blue-100) 70%, var(--color-white)); display: grid; place-items: center; color: var(--color-blue-500); flex: 0 0 auto; box-shadow: inset 0 0 0 1px var(--color-grey-100); }
.p-keytech-reusable-identity .ri-doc-thumb .ds-icon { width: 16px; height: 16px; }
.p-keytech-reusable-identity .ri-skip-row { display: flex; align-items: center; gap: 8px; padding: 8px 9px; border-radius: 8px; background: var(--color-white); box-shadow: inset 0 0 0 1px var(--color-grey-100); }

/* consent screen (v4) */
.p-keytech-reusable-identity .ri-consent { display: flex; flex-direction: column; gap: 7px; }
.p-keytech-reusable-identity .ri-consent__row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 9px; border-radius: 8px; background: var(--color-grey-50); box-shadow: inset 0 0 0 1px var(--color-grey-100); }

/* on-device screen (v5) */
.p-keytech-reusable-identity .ri-screen--ondevice { align-items: center; justify-content: space-between; text-align: center; }
.p-keytech-reusable-identity .ri-device-box { position: relative; margin: 6px auto; padding: 15px; border-radius: 14px; border: 1.5px dashed var(--color-blue-200); display: grid; place-items: center; }
.p-keytech-reusable-identity .ri-lock { position: absolute; right: -9px; bottom: -9px; width: 25px; height: 25px; border-radius: 50%; background: var(--color-white); box-shadow: inset 0 0 0 1px var(--color-grey-200); display: grid; place-items: center; color: var(--color-blue-500); }
.p-keytech-reusable-identity .ri-lock .ds-icon { width: 12px; height: 12px; }
.p-keytech-reusable-identity .ri-token-out { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px 4px 4px; border-radius: 999px; background: var(--color-grey-50); box-shadow: inset 0 0 0 1px var(--color-grey-100); }

/* step-up phone screen (v6) — matches the sibling phone cards (G12) */
.p-keytech-reusable-identity .ri-screen--stepup { align-items: center; justify-content: space-between; text-align: center; padding-block: 16px; }
.p-keytech-reusable-identity .ri-screen--stepup .ri-stack { align-items: center; }
.p-keytech-reusable-identity .ri-stepup-badge {
  width: 48px; height: 48px; border-radius: 14px; display: grid; place-items: center;
  background: color-mix(in oklab, var(--color-blue-100) 70%, var(--color-white)); color: var(--color-blue-500);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--color-blue-500) 20%, transparent);
}
.p-keytech-reusable-identity .ri-stepup-badge .ds-icon { width: 24px; height: 24px; }

/* dashboard step-up flow (v6, retired inline — kept for safety) */
.p-keytech-reusable-identity .ri-win--flow .ri-win__body { gap: 6px; }
.p-keytech-reusable-identity .ri-node { display: flex; align-items: center; gap: 8px; padding: 8px 9px; border-radius: 8px; background: var(--color-white); box-shadow: inset 0 0 0 1px var(--color-grey-100); }
.p-keytech-reusable-identity .ri-node__ic { width: 22px; height: 22px; border-radius: 6px; display: grid; place-items: center; background: var(--color-grey-100); color: var(--color-grey-400); flex: 0 0 auto; }
.p-keytech-reusable-identity .ri-node__ic .ds-icon { width: 13px; height: 13px; }
.p-keytech-reusable-identity .ri-node--decision { background: color-mix(in oklab, var(--color-blue-100) 55%, var(--color-white)); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--color-blue-500) 22%, transparent); }
.p-keytech-reusable-identity .ri-node--decision .ri-node__ic { background: var(--color-blue-100); color: var(--color-blue-500); }
.p-keytech-reusable-identity .ri-node--stepup .ri-node__ic { background: color-mix(in oklab, var(--color-blue-500) 14%, var(--color-white)); color: var(--color-blue-500); }
.p-keytech-reusable-identity .ri-branch { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.p-keytech-reusable-identity .ri-connector { width: 2px; height: 11px; margin-inline: auto; background: var(--color-grey-200); }

/* ============================================================
   v7 · PRIVACY diagram — verified identity travels as a tokenized
   credential (blue), the user consents (green check), PII is
   redacted. Replaces the doc-types world map. Light section, so
   the diagram sits on a white card.
   ============================================================ */
.p-keytech-reusable-identity .ri-mock--privacy { max-width: 480px; margin-inline: auto; }
.p-keytech-reusable-identity .ri-priv { position: relative; display: grid; grid-template-columns: 1fr 1.3fr 1fr; align-items: center; gap: 8px; padding: 26px 20px; border-radius: 18px; background: var(--color-white); box-shadow: inset 0 0 0 1px var(--color-grey-100); }
.p-keytech-reusable-identity .ri-priv::before, .p-keytech-reusable-identity .ri-priv::after { content: ""; position: absolute; top: 50%; height: 2px; width: 11%; background: var(--color-grey-200); }
.p-keytech-reusable-identity .ri-priv::before { left: 27%; }
.p-keytech-reusable-identity .ri-priv::after { right: 27%; }
.p-keytech-reusable-identity .ri-priv__node { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; gap: 9px; text-align: center; }
.p-keytech-reusable-identity .ri-priv__ic { width: 46px; height: 46px; border-radius: 13px; display: grid; place-items: center; background: var(--color-grey-50); box-shadow: inset 0 0 0 1px var(--color-grey-100); color: var(--color-grey-400); }
.p-keytech-reusable-identity .ri-priv__ic .ds-icon { width: 22px; height: 22px; }
.p-keytech-reusable-identity .ri-priv__node--user .ri-priv__ic { background: color-mix(in oklab, var(--color-blue-100) 60%, var(--color-white)); color: var(--color-blue-500); }
.p-keytech-reusable-identity .ri-priv__mid { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; gap: 9px; }
.p-keytech-reusable-identity .ri-priv__token { width: 42px; height: 42px; border-radius: 50%; display: grid; place-items: center; background: var(--color-blue-500); color: var(--color-white); box-shadow: none; }
.p-keytech-reusable-identity .ri-priv__token .ds-icon { width: 20px; height: 20px; }
.p-keytech-reusable-identity .ri-priv__chip { display: inline-flex; align-items: center; gap: 6px; padding: 4px 11px 4px 4px; border-radius: 999px; background: var(--color-grey-50); box-shadow: inset 0 0 0 1px var(--color-grey-100); }
.p-keytech-reusable-identity .ri-priv__redact { display: inline-flex; align-items: center; gap: 8px; }
.p-keytech-reusable-identity .ri-priv__redact .ri-strike::after { background: var(--color-grey-400); }
.p-keytech-reusable-identity .ri-priv__lock { width: 20px; height: 20px; border-radius: 50%; display: grid; place-items: center; background: var(--color-grey-100); color: var(--color-grey-400); flex: 0 0 auto; }
.p-keytech-reusable-identity .ri-priv__lock .ds-icon { width: 12px; height: 12px; }

/* ---- threat: cloned source line (both stats are load-bearing) ---- */
.p-keytech-reusable-identity .dv-threat__src {
  margin-top: 12px;
  font-size: var(--fs-xs);
  letter-spacing: var(--track-wide);
  color: rgba(255, 255, 255, 0.4);
}

/* ---- impact (dv-deepsight clone-swap): breathing room for the copy
        column now that the support paragraph leads without an intro ---- */
.p-keytech-reusable-identity .dv-deepsight__support { margin-top: 20px; }

/* ---- stats band (G6): 4 counters must hold ONE row at 1440 AND 1280.
        Tighten the value ramp + gap so "1 selfie" never wraps a cell. ---- */
@media (min-width: 768px) {
  .p-keytech-reusable-identity .dv-stats__grid { gap: 28px; }
  .p-keytech-reusable-identity .dv-stats__item { padding-left: 24px; }
  .p-keytech-reusable-identity .dv-stats__value { font-size: clamp(34px, 3.5vw, 46px); }
}

/* ---- reduced motion: rest the ambient hero/dual animations ---- */
@media (prefers-reduced-motion: reduce) {
  .p-keytech-reusable-identity .ri-face__sweep { animation: none; opacity: 0; }
  .p-keytech-reusable-identity .ri-dual__link-pulse { animation: none; opacity: 0; }
}

/* ============================================================
   8b · REUSE CONSOLE — "In the review dashboard" step-walk.
   ADDED after the PRIVACY section (2026-08-07). Shows + talks
   about the operator dashboard for a returning, already-verified
   user: the session resolves to a recognized identity whose prior
   verification is reused (single selfie), with the full audit trail.

   The interaction + card kit are copied verbatim from the KYC-AML
   "Screening" and KYB "reviewer's view" sections (at-how__* deck +
   sol-how__* rail, driven by section-walk.js) so this page reads as
   one system with them. The sol-how__* RAIL styles come free from
   solution.css via a .p-solution wrapper around the section (that
   sheet is already loaded on this page). The at-how__* DECK styles
   live in kyc-aml.css (NOT loaded here), so they are copied below,
   rescoped to .p-keytech-reusable-identity .ri-console — the extra
   class keeps every rule at a higher specificity than solution.css,
   so it wins regardless of pageCss load order. Tokens only.
   ============================================================ */
.p-keytech-reusable-identity .ri-console {
  background: var(--color-white);
  color: var(--color-foreground);
  border-top: 1px solid var(--color-border-light);
}

/* jump-free rail: every 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. */
.p-keytech-reusable-identity .ri-console .sol-how__reveal {
  display: block;
  height: 0;
  overflow: hidden;
  transition: height 0.45s cubic-bezier(0.23, 1, 0.32, 1);
}
.p-keytech-reusable-identity .ri-console .sol-how__step.is-active .sol-how__reveal {
  height: var(--at-reveal-h, 78px);
}
.p-keytech-reusable-identity .ri-console .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, so scroll SELECTS the step. */
.p-keytech-reusable-identity .ri-console__pin { position: relative; }
.p-keytech-reusable-identity .ri-console.is-walk {
  height: calc(100svh + 72svh * var(--ka-steps, 4));
}
.p-keytech-reusable-identity .ri-console.is-walk .ri-console__pin {
  position: sticky;
  top: 0;
  min-height: 100svh;
  display: flex;
  align-items: center;
}

/* active-step underline. Walk mode tracks the in-band scroll fraction
   (--ka-scrub). Static mode: a timed fill matching auto-advance
   (sol-how-fill keyframes live in solution.css). */
.p-keytech-reusable-identity .ri-console.is-walk .sol-how__step.is-active .sol-how__fill {
  transform: scaleX(var(--ka-scrub, 0));
  transition: transform 0.18s linear;
}
/* only the ACTIVE bullet carries the blue line (Camila 2026-08-08) — done
   steps drop back to the hairline, matching the page's #how walk. */
.p-keytech-reusable-identity .ri-console.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-reusable-identity .ri-console: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-reusable-identity .ri-console:not(.is-walk) .sol-how__step.is-active .sol-how__fill { animation: none; }
}

/* the deck — a constant-height slot the stage centers (the card grows
   downward, top edge holds still) with a card whose height morphs to the
   active screen. */
.p-keytech-reusable-identity .ri-console .at-how__slot {
  width: min(100%, 420px);
  height: var(--at-slot-h, auto);
}
.p-keytech-reusable-identity .ri-console .at-how__deck {
  position: relative;
  display: grid;
  width: 100%;
  height: var(--at-screen-h, auto);
  overflow: hidden;
  border-radius: 16px;
  border: 1px solid var(--color-border-light);
  background: var(--color-white);
  box-shadow: none;
  transition: height 0.45s cubic-bezier(0.23, 1, 0.32, 1);
}
.p-keytech-reusable-identity .ri-console .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;
  pointer-events: none;
}
.p-keytech-reusable-identity .ri-console .at-how__screen.is-active {
  opacity: 1;
  transition: opacity 0.35s ease 0.05s;
}
@media (prefers-reduced-motion: reduce) {
  .p-keytech-reusable-identity .ri-console .at-how__deck,
  .p-keytech-reusable-identity .ri-console .at-how__screen,
  .p-keytech-reusable-identity .ri-console .sol-how__reveal {
    transition: none;
  }
}

/* screen chrome */
.p-keytech-reusable-identity .ri-console .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-reusable-identity .ri-console .at-how__head .ds-icon {
  width: 18px;
  height: 18px;
  color: var(--color-grey-400);
}
.p-keytech-reusable-identity .ri-console .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;
}
.p-keytech-reusable-identity .ri-console .at-how__pill--accent {
  background: color-mix(in oklab, var(--color-blue-500) 14%, transparent);
  color: var(--color-blue);
}
.p-keytech-reusable-identity .ri-console .at-how__row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: auto;
}

/* recognized / reuse lanes */
.p-keytech-reusable-identity .ri-console .at-how__lane {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid var(--color-border-light);
  background: var(--color-grey-50);
}
.p-keytech-reusable-identity .ri-console .at-how__lane--flag {
  border-color: color-mix(in oklab, var(--color-blue) 40%, transparent);
  background: var(--color-blue-100);
}
.p-keytech-reusable-identity .ri-console .at-how__lane-glyph {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  border: 1px solid var(--color-border-light);
  background: var(--color-white);
  color: var(--color-grey-500);
}
.p-keytech-reusable-identity .ri-console .at-how__lane--flag .at-how__lane-glyph {
  border-color: color-mix(in oklab, var(--color-blue) 30%, transparent);
  color: var(--color-blue);
}
.p-keytech-reusable-identity .ri-console .at-how__lane-glyph .ds-icon { width: 20px; height: 20px; }
.p-keytech-reusable-identity .ri-console .at-how__lane-label {
  flex: 1;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--color-foreground);
}

/* consent / step-up card (the real modal in miniature): one action, a
   required field, a Deny / Approve pair */
.p-keytech-reusable-identity .ri-console .at-how__consent {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-lg);
  background: var(--color-grey-50);
}
.p-keytech-reusable-identity .ri-console .at-how__consent-h {
  font-size: 12.5px;
  font-weight: 600;
  text-align: center;
  color: var(--color-grey-600);
}
.p-keytech-reusable-identity .ri-console .at-how__consent-perm {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 11px;
  border: 1px solid var(--color-border-light);
  border-radius: 9px;
  background: var(--color-white);
}
.p-keytech-reusable-identity .ri-console .at-how__consent-perm > span {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--color-grey-600);
}
.p-keytech-reusable-identity .ri-console .at-how__consent-perm b {
  flex: none;
  padding: 2px 7px;
  border: 1px solid var(--color-border-light);
  border-radius: 999px;
  font-size: 9px;
  font-weight: 600;
  white-space: nowrap;
  color: var(--color-grey-400);
}
.p-keytech-reusable-identity .ri-console .at-how__consent-actions { display: flex; gap: 8px; }
.p-keytech-reusable-identity .ri-console .at-how__consent-deny,
.p-keytech-reusable-identity .ri-console .at-how__consent-approve {
  flex: 1;
  padding: 7px 0;
  border-radius: var(--radius-md);
  font-size: 11.5px;
  font-weight: 600;
  text-align: center;
}
.p-keytech-reusable-identity .ri-console .at-how__consent-deny {
  border: 1px solid var(--color-grey-200);
  background: var(--color-white);
  color: var(--color-grey-400);
}
.p-keytech-reusable-identity .ri-console .at-how__consent-approve {
  background: var(--color-blue);
  color: var(--color-white);
  font-weight: 700;
}

/* audit trail / module rows — dot + label + status pill */
.p-keytech-reusable-identity .ri-console .at-how__audit {
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.p-keytech-reusable-identity .ri-console .at-how__audit-row {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 12px;
  border: 1px solid var(--color-border-light);
  border-radius: 10px;
  background: var(--color-white);
}
.p-keytech-reusable-identity .ri-console .at-how__audit-row > span {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--color-grey-600);
}
.p-keytech-reusable-identity .ri-console .at-how__audit-dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-grey-300);
}
.p-keytech-reusable-identity .ri-console .at-how__audit-dot--ok { background: var(--color-green-500); }
.p-keytech-reusable-identity .ri-console .at-how__audit-dot--flag { background: var(--color-red-500); }
.p-keytech-reusable-identity .ri-console .at-how__audit-pill {
  flex: none;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 9.5px;
  font-weight: 600;
  background: var(--color-grey-100);
  color: var(--color-grey-on-white);
}
.p-keytech-reusable-identity .ri-console .at-how__audit-pill--ok {
  background: color-mix(in oklab, var(--color-green-500) 13%, transparent);
  color: var(--color-green-600);
}
.p-keytech-reusable-identity .ri-console .at-how__audit-pill--warn {
  background: color-mix(in oklab, var(--color-amber-600) 15%, transparent);
  color: var(--color-amber-600);
}
.p-keytech-reusable-identity .ri-console .at-how__audit-pill--flag {
  background: color-mix(in oklab, var(--color-red-400) 15%, transparent);
  color: var(--color-red-500);
}

/* match-score meter row (reuses the page's ri-meter primitive inside a lane) */
.p-keytech-reusable-identity .ri-console .at-how__score { display: flex; align-items: center; gap: 12px; }
.p-keytech-reusable-identity .ri-console .at-how__score .ri-meter { flex: 1; }
.p-keytech-reusable-identity .ri-console .at-how__score-val {
  flex: none;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--color-blue);
  font-variant-numeric: tabular-nums;
}

/* copy header: keep the intro to a comfortable measure */
.p-keytech-reusable-identity .ri-console .sol-how__rail .sol-intro { max-width: 42ch; }

/* ============================================================
   REUSE-CONSOLE deck — the locked "Single Session dashboard"
   template (liveness-detection lvw-*) rescoped here as rid-*
   under .p-keytech-reusable-identity .ri-console. A light browser
   window → grey-line nav → green "Pass" header → a persistent
   round FACE avatar (selfie loop) on the LEFT + crossfading console
   screens on the RIGHT. Rows are unified hairline label · pill,
   no boxes, hairline separators. Only the SCROLL-WALK deck (plain
   .ri-console, data-ka-walk) uses these; the DUAL section's static
   card keeps the older at-how__* kit above. Tokens only.
   The scroll-walk mechanic is unchanged — section-walk.js still
   toggles .is-active on [data-at-screen]; screens overlap in a grid
   cell so the deck holds a stable height without the at-how height
   morph. Widen this stage's columns so the 640px window breathes
   (scoped to .ri-console so the page's #how walk keeps its balance).
   ============================================================ */
@media (min-width: 1024px) {
  .p-keytech-reusable-identity .ri-console .sol-how__inner {
    grid-template-columns: minmax(0, 0.74fr) minmax(0, 1.26fr);
    gap: 56px;
  }
}
.p-keytech-reusable-identity .ri-console .rid-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 now comes from the canonical BrowserChrome component
   (components/browser-chrome.css) — the bespoke .rid-chrome CSS was removed */
/* dashboard inside the window: de-emphasised nav + main */
.p-keytech-reusable-identity .ri-console .rid-app {
  display: flex;
  align-items: stretch;
  min-height: 300px;
}
.p-keytech-reusable-identity .ri-console .rid-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-reusable-identity .ri-console .rid-appnav__line {
  height: 7px; border-radius: 999px; background: var(--color-grey-200);
}
.p-keytech-reusable-identity .ri-console .rid-appmain {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column;
}
.p-keytech-reusable-identity .ri-console .rid-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-reusable-identity .ri-console .rid-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-reusable-identity .ri-console .rid-apphead__sid {
  font-size: 12px; font-weight: 500; color: var(--color-grey-400);
}
.p-keytech-reusable-identity .ri-console .rid-body {
  display: flex;
  align-items: stretch;
  flex: 1;
  min-width: 0;
}
/* ---- face capture (left) — a persistent round selfie-loop avatar ---- */
.p-keytech-reusable-identity .ri-console .rid-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-reusable-identity .ri-console .rid-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-reusable-identity .ri-console .rid-face__cam {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
/* ---- console screens (right) — crossfade in a single grid cell so the
   deck height stays stable across steps (tallest screen sets it) ---- */
.p-keytech-reusable-identity .ri-console .rid-screens {
  position: relative;
  display: grid;
  flex: 1;
  min-width: 0;
  align-self: stretch;
}
.p-keytech-reusable-identity .ri-console .rid-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-reusable-identity .ri-console .rid-screen.is-active {
  opacity: 1;
  transition: opacity 0.35s ease 0.05s;
}
.p-keytech-reusable-identity .ri-console .rid-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--color-grey-on-white);
}
.p-keytech-reusable-identity .ri-console .rid-head .ds-icon { width: 18px; height: 18px; color: var(--color-grey-400); }

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

/* tone pills — green for pass/valid, red for negative, plus a neutral
   grey and a blue accent for descriptor values (1:N, Universal Identity…) */
.p-keytech-reusable-identity .ri-console .rid-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-reusable-identity .ri-console .rid-pill--good { background: var(--color-green-100); color: var(--color-green-600); }
.p-keytech-reusable-identity .ri-console .rid-pill--bad { background: var(--color-red-100); color: var(--color-red-600); }
.p-keytech-reusable-identity .ri-console .rid-pill--muted { background: var(--color-grey-100); color: var(--color-grey-on-white); }
.p-keytech-reusable-identity .ri-console .rid-pill--accent {
  background: color-mix(in oklab, var(--color-blue-500) 14%, transparent);
  color: var(--color-blue);
}

/* footer accent chip row */
.p-keytech-reusable-identity .ri-console .rid-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: auto;
}
.p-keytech-reusable-identity .ri-console .rid-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-reusable-identity .ri-console .rid-chip--accent {
  background: color-mix(in oklab, var(--color-blue-500) 14%, transparent);
  color: var(--color-blue);
}

/* choreography — pills pop on each activation */
.p-keytech-reusable-identity .ri-console .rid-screen .rid-pill { opacity: 0; transform: translateY(3px) scale(0.9); }
.p-keytech-reusable-identity .ri-console .rid-screen.is-active .rid-pill {
  animation: rid-pop 0.45s cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: var(--d, 0s);
}
@keyframes rid-pop {
  from { opacity: 0; transform: translateY(3px) scale(0.9); }
  to { opacity: 1; transform: none; }
}
/* mobile: the deck no longer reflows — dashFit (site.js, data-dash-fit on
   both .rid-deck instances) renders the exact 640px desktop layout scaled
   down to the column, so the nav stays BESIDE the console exactly as on
   desktop (applies to both the scroll-walk and the static deck) */
@media (prefers-reduced-motion: reduce) {
  .p-keytech-reusable-identity .ri-console .rid-screen { transition: none; }
  .p-keytech-reusable-identity .ri-console .rid-screen .rid-pill {
    animation: none !important;
    opacity: 1;
    transform: none;
  }
}

/* ============================================================
   STATIC "Instant Verify" window — the DUAL section's "Your team's
   side" shows the SAME rid-* browser-window template as the
   #reuse-console scroll-walk deck (chrome → grey-line nav → green
   "Pass" header → round face avatar + hairline label·pill rows), so
   both read as one product. No walk, no data-ka-walk, so
   section-walk.js ignores it; the lone screen is .is-active so it
   holds at opacity 1. These overrides only strip the section chrome
   (border-top / block bg) the base .ri-console rule would add; the
   rid-deck sizes + centers itself (width: min(100%, 640px);
   margin-inline: auto) in the right column.
   ============================================================ */
.p-keytech-reusable-identity .ri-console--static {
  border-top: 0;
  background: transparent;
}

/* vertically center the card in its (taller) column, deliberate against
   the user's phone side, while the caption stays top-aligned with it */
@media (min-width: 900px) {
  .p-keytech-reusable-identity .ri-dual__stage > .ri-dual__side:last-child {
    align-self: stretch;
    display: flex;
    flex-direction: column;
  }
  .p-keytech-reusable-identity .ri-dual__side .ri-console--static { margin-block: auto; }
}

/* ═════════════════════════════════════════════════════════════════════════
   HOW-IT-WORKS walk · ri-sf scaffold — Camila 2026-08-07.
   The account-takeover at-sf floating-container pattern, standalone flavor:
   this page's walk (HowItWorks markup inlined in the .astro) has NO
   traveling phone, so the float layer lives INSIDE .sol-how__stage — no
   z-order twin needed (the twin only exists to beat a phonecol clone's
   z-index). Visibility keys off the ACTIVE RAIL BUTTON via :has() rooted
   at .sol-how (the common ancestor of rail and floats), no JS.
   Per-step content + fine positioning live in the per-step lane blocks
   below (one sub-agent each).
   ═════════════════════════════════════════════════════════════════════════ */
/* (page-scoped standalone stage fix removed 2026-08-07 — the global
   :not([data-sol-standalone]) guard landed in solution.css via upstream) */
.p-keytech-reusable-identity .sol-how__stage { position: relative; }
.p-keytech-reusable-identity .ri-sf-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* in front of the phone (same stacking context — no sticky pin between
     the floats and the phone on a standalone walk) */
  z-index: 5;
}
.p-keytech-reusable-identity .ri-sf {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition:
    opacity 0.45s var(--ease-out-expo),
    transform 0.45s var(--ease-out-expo),
    visibility 0s 0.45s;
}
.p-keytech-reusable-identity .sol-how:has(.sol-how__step.is-active[data-sol-step="0"]) .ri-sf[data-at-sf="0"],
.p-keytech-reusable-identity .sol-how:has(.sol-how__step.is-active[data-sol-step="1"]) .ri-sf[data-at-sf="1"],
.p-keytech-reusable-identity .sol-how:has(.sol-how__step.is-active[data-sol-step="2"]) .ri-sf[data-at-sf="2"],
.p-keytech-reusable-identity .sol-how:has(.sol-how__step.is-active[data-sol-step="3"]) .ri-sf[data-at-sf="3"],
.p-keytech-reusable-identity .sol-how:has(.sol-how__step.is-active[data-sol-step="4"]) .ri-sf[data-at-sf="4"] {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0.15s, 0.15s, 0.15s;
}
/* only the ACTIVE bullet carries the blue rail line — the shared template
   holds a full blue bar on walked-past steps; here done steps go back to
   the hairline (the account-takeover rule). */
.p-keytech-reusable-identity .sol-flow-wrap.is-float .sol-how__step.is-done .sol-how__fill {
  transform: scaleX(0);
  transition: transform 0.4s ease;
}
/* shared float-card look — the at-sf__card construction (white card,
   hairline border, stacked uppercase label) at walk scale */
.p-keytech-reusable-identity .ri-sf__card {
  position: absolute;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 16px;
  border: 1px solid var(--color-border-light);
  border-radius: 14px;
  background: var(--color-white);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  color: var(--color-grey-500);
  white-space: nowrap;
}
.p-keytech-reusable-identity .ri-sf__label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-grey-400);
}
@media (max-width: 899px) {
  .p-keytech-reusable-identity .ri-sf-layer { display: none; }
}

/* (ri-hero lane removed 2026-08-07 — upstream owner order dropped the hero
   foot visual; the live-selfie hero composite lives in git stash history) */

/* ═══ ri-s0 · step 1 "Verify" (agent lane: step-0) — rules below ═══ */

/* deck screen 0 — inline-SVG IdCapture3Screen. On activation the license
   card rides up into the capture frame (dim outside, lit inside — the
   dual-copy light mask baked into the component), then the frame settles
   green as the last check on the float card resolves. Replays on every
   activation because it's keyed to .is-active (toggled per step by
   solution-hero.js). Rest / reduced motion = card seated, frame blue. */
@media (prefers-reduced-motion: no-preference) {
  .p-keytech-reusable-identity .ri-s0-screen.is-active .idc-card,
  .p-keytech-reusable-identity .ri-s0-screen.is-active .idc-card-lit {
    animation: ri-s0-card-in 1.5s cubic-bezier(0.85, 0, 0.25, 1) 0.25s both;
  }
  .p-keytech-reusable-identity .ri-s0-screen.is-active .idc-frame path {
    animation: ri-s0-frame-success 0.5s ease 2.5s both;
  }
}
@keyframes ri-s0-card-in {
  from { transform: translateY(228px); } /* card top ≈ 15px below the frame's bottom edge */
  to { transform: translateY(0); }
}
@keyframes ri-s0-frame-success {
  to { stroke: var(--color-green-500); }
}

/* float card — "Onboarding-grade check": three checks resolving
   sequentially (busy ring → green check), the canonical timed-resolve
   pattern. Anchored to the stage's LEFT edge, riding the lower band of
   the screen (below "All data is encrypted", above the help button) so
   it never covers the heading or the capture frame. */
.p-keytech-reusable-identity .ri-s0-card {
  left: 10px;
  top: 63%;
  max-width: calc(100% - 20px); /* excess width eats inward, never outward */
}
.p-keytech-reusable-identity .ri-s0-checks {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.p-keytech-reusable-identity .ri-s0-check {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  font-size: 11px;
  line-height: 1.35;
  font-weight: 600;
  color: var(--color-grey-500);
}
/* rest state = resolved: green disc + white check. The busy ring
   (::before, the card's single blue accent) only shows mid-animation. */
.p-keytech-reusable-identity .ri-s0-dot {
  position: relative;
  flex: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 1.5px solid var(--color-green-500);
  background: var(--color-green-500);
}
.p-keytech-reusable-identity .ri-s0-dot::before {
  content: "";
  position: absolute;
  inset: -1.5px;
  border-radius: 50%;
  border: 1.5px solid var(--color-grey-200);
  border-top-color: var(--color-blue-500);
  opacity: 0;
}
.p-keytech-reusable-identity .ri-s0-dot::after {
  content: "";
  position: absolute;
  inset: 3px;
  background: var(--color-white);
  -webkit-mask: url(/icons/check.svg) center / contain no-repeat;
  mask: url(/icons/check.svg) center / contain no-repeat;
}
@media (prefers-reduced-motion: no-preference) {
  .p-keytech-reusable-identity .ri-s0-check:nth-child(1) { --ri-s0-d: 0.7s; }
  .p-keytech-reusable-identity .ri-s0-check:nth-child(2) { --ri-s0-d: 1.5s; }
  .p-keytech-reusable-identity .ri-s0-check:nth-child(3) { --ri-s0-d: 2.3s; }
  .p-keytech-reusable-identity .sol-how:has(.sol-how__step.is-active[data-sol-step="0"]) .ri-s0-dot {
    animation: ri-s0-resolve 0.01s linear var(--ri-s0-d) both;
  }
  .p-keytech-reusable-identity .sol-how:has(.sol-how__step.is-active[data-sol-step="0"]) .ri-s0-dot::before {
    opacity: 1;
    animation: ri-s0-busy-spin 0.7s linear infinite, ri-s0-busy-out 0.2s linear var(--ri-s0-d) forwards;
  }
  .p-keytech-reusable-identity .sol-how:has(.sol-how__step.is-active[data-sol-step="0"]) .ri-s0-dot::after {
    animation: ri-s0-check-pop 0.35s var(--ease-out-expo) var(--ri-s0-d) both;
  }
}
@keyframes ri-s0-resolve {
  from { background: var(--color-white); border-color: var(--color-grey-200); }
  to { background: var(--color-green-500); border-color: var(--color-green-500); }
}
@keyframes ri-s0-busy-spin {
  to { transform: rotate(1turn); }
}
@keyframes ri-s0-busy-out {
  to { opacity: 0; }
}
@keyframes ri-s0-check-pop {
  from { opacity: 0; transform: scale(0.4); }
  to { opacity: 1; transform: none; }
}

/* ═══ ri-s1 · step 2 "Enroll" (agent lane: step-1) — rules below ═══ */

/* deck slot 1 · real verifying capture with a LIVE spinner overlaid exactly
   on the capture's baked-in ring (measured on the 780×1688 source). The
   mask disc paints screen-white over the baked arc (incl. its soft shadow),
   then the track + rotating arc redraw it live. */
.p-keytech-reusable-identity .ri-s1-screen { position: relative; overflow: hidden; }
.p-keytech-reusable-identity .ri-s1-screen__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  border-radius: 34px;
}
.p-keytech-reusable-identity .ri-s1-spinbox {
  position: absolute;
  left: 50%;
  top: 48.34%;
  width: 12.4%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  display: grid;
}
/* mask disc reaches past the viewBox to hide the baked arc's soft shadow */
.p-keytech-reusable-identity .ri-s1-spin { width: 100%; height: 100%; display: block; overflow: visible; }
.p-keytech-reusable-identity .ri-s1-spin__mask { fill: var(--color-white); }
.p-keytech-reusable-identity .ri-s1-spin__track,
.p-keytech-reusable-identity .ri-s1-spin__arc { fill: none; stroke-width: 15; }
.p-keytech-reusable-identity .ri-s1-spin__track { stroke: var(--color-blue-100); }
.p-keytech-reusable-identity .ri-s1-spin__arc {
  stroke: var(--color-blue-500);
  stroke-linecap: round;
  stroke-dasharray: 25 75;
  stroke-dashoffset: 25;
}
@media (prefers-reduced-motion: no-preference) {
  .p-keytech-reusable-identity .ri-s1-screen.is-active .ri-s1-spin { animation: ri-s1-spin 1.1s linear infinite; }
}
@keyframes ri-s1-spin { to { transform: rotate(1turn); } }

/* float card · "Encrypted credential" — rides the phone's lower-right,
   beside the capture's empty band below the caption (core content —
   spinner / heading / caption — sits ~44–62% of the screen; card stays
   below it). Lock chip is the single blue accent; it pops/settles each
   time the step activates (selector unmatches on deactivation, so the
   animation replays). Reduced motion: settled state, no pop. */
.p-keytech-reusable-identity .ri-s1-cred {
  right: 10px;
  top: 63%;
  /* Camila feedback 2026-08-07: narrower card — fixed 190px, body wraps */
  width: 190px;
  max-width: calc(100% - 20px);
  white-space: normal;
}
.p-keytech-reusable-identity .ri-s1-cred__line { line-height: 1.45; }
.p-keytech-reusable-identity .ri-s1-cred__head {
  display: flex;
  align-items: center;
  gap: 8px;
}
.p-keytech-reusable-identity .ri-s1-cred__chip {
  flex: none;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 8px;
  background: var(--color-blue-500);
  color: var(--color-white);
}
.p-keytech-reusable-identity .ri-s1-cred__chip .ds-icon { width: 13px; height: 13px; }
@media (prefers-reduced-motion: no-preference) {
  .p-keytech-reusable-identity .sol-how:has(.sol-how__step.is-active[data-sol-step="1"]) .ri-s1-cred__chip {
    animation: ri-s1-chip-pop 0.55s var(--ease-out-expo) 0.35s backwards;
  }
}
@keyframes ri-s1-chip-pop {
  0% { transform: scale(0.3); opacity: 0; }
  62% { transform: scale(1.12); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}

/* ═══ ri-s2 · step 3 "Recognize" (agent lane: step-2) — rules below ═══ */

/* deck slot 2 — the LIVE recognize composite: real Selfie3 screen with the
   selfie video clipped into its capture circle, blue gradient ring spinning */
.p-keytech-reusable-identity .ri-s2-screen { position: relative; overflow: hidden; }
.p-keytech-reusable-identity .ri-s2-screen .ri-s2-svg { display: block; width: 100%; height: auto; }
/* video replaces the static face; caption + grey ring track stay */
.p-keytech-reusable-identity .ri-s2-screen .s3-photo,
.p-keytech-reusable-identity .ri-s2-screen .s3-scene,
.p-keytech-reusable-identity .ri-s2-screen .s3-silhouette,
.p-keytech-reusable-identity .ri-s2-screen .s3-caption-ready { display: none; } /* the alternate caption renders by default — hide per instance or both captions superimpose */
/* video clipped to the capture circle — 390×844 viewBox, circle cx195 cy313.5 r145.5 */
.p-keytech-reusable-identity .ri-s2-cam {
  position: absolute;
  left: 12.692%;
  top: 19.905%;
  width: 74.615%;
  height: 34.479%;
  border-radius: 50%;
  object-fit: cover;
  background: var(--color-grey-50);
}
/* the screen's own blue gradient capture ring, revealed + spinning */
.p-keytech-reusable-identity .ri-s2-screen .s3-ring-scan { display: inline; transform-box: fill-box; transform-origin: center; }
@media (prefers-reduced-motion: no-preference) {
  .p-keytech-reusable-identity .ri-s2-screen .s3-ring-scan { animation: ri-s2-ring-spin 2.4s linear infinite; }
}
@keyframes ri-s2-ring-spin { to { transform: rotate(1turn); } }

/* float card — recognition status: spinner resolves to a check each time
   the step lands */
.p-keytech-reusable-identity .ri-s2-card {
  /* below the screen caption's last line (bottom ≈ 66% of the stage at
     1280–1728) and right of the "verified by incode" footer + home bar,
     so the ride onto the phone covers only blank screen */
  right: 10px;
  top: 66.5%;
  width: 176px;
  max-width: calc(100% - 20px);
  white-space: normal;
}
.p-keytech-reusable-identity .ri-s2-line { line-height: 1.45; }
.p-keytech-reusable-identity .ri-s2-slot { display: grid; place-items: center; width: 16px; height: 16px; flex-shrink: 0; }
.p-keytech-reusable-identity .ri-s2-slot > svg { grid-area: 1 / 1; width: 16px; height: 16px; }
.p-keytech-reusable-identity .ri-s2-spin-track { stroke: var(--color-blue-100); }
.p-keytech-reusable-identity .ri-s2-spin-arc { stroke: var(--color-blue-500); stroke-linecap: round; stroke-dasharray: 30 70; }
.p-keytech-reusable-identity .ri-s2-checkmark { opacity: 0; color: var(--color-blue-500); }
@media (prefers-reduced-motion: no-preference) {
  .p-keytech-reusable-identity .sol-how:has(.sol-how__step.is-active[data-sol-step="2"]) .ri-s2-spinner { animation: ri-s2-spin 0.9s linear infinite, ri-s2-spin-out 0.25s ease 2.15s both; }
  .p-keytech-reusable-identity .sol-how:has(.sol-how__step.is-active[data-sol-step="2"]) .ri-s2-checkmark { animation: ri-s2-check-in 0.35s var(--ease-out-expo) 2.3s both; }
}
@media (prefers-reduced-motion: reduce) {
  .p-keytech-reusable-identity .ri-s2-spinner { display: none; }
  .p-keytech-reusable-identity .ri-s2-checkmark { opacity: 1; }
}
@keyframes ri-s2-spin { to { transform: rotate(1turn); } }
@keyframes ri-s2-spin-out { to { opacity: 0; } }
@keyframes ri-s2-check-in { from { opacity: 0; transform: scale(0.4); } to { opacity: 1; transform: none; } }

/* ═══ ri-s3 · step 4 "Reuse" (agent lane: step-3) — rules below ═══ */

/* deck screen: the inline vector Success! screen (Selfie7Screen). The
   static filled check is the resting/reduced-motion state; with motion
   the stroked twin (.s7-check-draw, pathLength=1) draws on and the green
   badge pops each time the step activates (keyed off the active rail
   button via :has(), so it replays on every return to the step). */
@media (prefers-reduced-motion: no-preference) {
  .p-keytech-reusable-identity .ri-s3-screen .s7-check { display: none; }
  .p-keytech-reusable-identity .ri-s3-screen .s7-check-draw {
    display: inline;
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
  }
  .p-keytech-reusable-identity .ri-s3-screen .s7-badge {
    transform-box: fill-box;
    transform-origin: center;
    transform: scale(0.5);
    opacity: 0;
  }
  .p-keytech-reusable-identity .sol-how:has(.sol-how__step.is-active[data-sol-step="3"]) .ri-s3-screen .s7-badge {
    animation: ri-s3-badge-pop 0.6s cubic-bezier(0, 0.75, 0.25, 1) 0.25s forwards;
  }
  .p-keytech-reusable-identity .sol-how:has(.sol-how__step.is-active[data-sol-step="3"]) .ri-s3-screen .s7-check-draw {
    animation: ri-s3-check-draw 0.3s ease-out 0.6s forwards;
  }
}
@keyframes ri-s3-badge-pop {
  0% { opacity: 1; }
  80% { transform: scale(1.06); opacity: 1; }
  to { transform: scale(1); opacity: 1; }
}
@keyframes ri-s3-check-draw {
  to { stroke-dashoffset: 0; }
}

/* float cards — consent card right of the phone, carry chip upper-left.
   Camila feedback 2026-08-07: both were too wide — fixed narrow widths,
   lines wrap. */
.p-keytech-reusable-identity .ri-s3-consent {
  right: 10px;
  top: 56%;
  width: 200px;
  max-width: calc(100% - 20px);
  white-space: normal;
}
.p-keytech-reusable-identity .ri-s3-carry {
  left: 10px;
  /* 24.5% threads the blank band between the screen's wordmark and its
     green badge at 1280/1440/1728 (measured 2026-08-07) */
  top: 24.5%;
  width: 172px;
  max-width: calc(100% - 20px);
  padding: 10px 14px;
  white-space: normal;
}
.p-keytech-reusable-identity .ri-s3-line { line-height: 1.45; }
.p-keytech-reusable-identity .ri-s3-row {
  display: inline-flex;
  /* flex-start so chips/toggle top-align when the line wraps (narrow cards) */
  align-items: flex-start;
  gap: 8px;
}
.p-keytech-reusable-identity .ri-s3-row .ri-s3-toggle { margin-top: 2px; }
.p-keytech-reusable-identity .ri-s3-chip {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: var(--color-grey-50);
  border: 1px solid var(--color-border-light);
  color: var(--color-grey-500);
}
.p-keytech-reusable-identity .ri-s3-chip .ds-icon {
  width: 16px;
  height: 16px;
}
/* the carry chip's single blue accent */
.p-keytech-reusable-identity .ri-s3-chip--blue {
  background: var(--color-blue-100);
  border-color: color-mix(in oklab, var(--color-blue-500) 18%, transparent);
  color: var(--color-blue-500);
}
/* consent toggle — the card's single blue accent; resting/reduced-motion
   state is settled ON, with motion it flips on after the card lands */
.p-keytech-reusable-identity .ri-s3-toggle {
  flex: none;
  position: relative;
  display: inline-block;
  width: 32px;
  height: 18px;
  border-radius: 999px;
  background: var(--color-blue-500);
}
.p-keytech-reusable-identity .ri-s3-toggle__knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--color-white);
  transform: translateX(14px);
}
@media (prefers-reduced-motion: no-preference) {
  .p-keytech-reusable-identity .ri-s3-toggle {
    background: var(--color-grey-200);
    transition: background 0.3s ease;
  }
  .p-keytech-reusable-identity .ri-s3-toggle__knob {
    transform: none;
    transition: transform 0.3s var(--ease-out-expo);
  }
  .p-keytech-reusable-identity .sol-how:has(.sol-how__step.is-active[data-sol-step="3"]) .ri-s3-toggle {
    background: var(--color-blue-500);
    transition-delay: 0.8s;
  }
  .p-keytech-reusable-identity .sol-how:has(.sol-how__step.is-active[data-sol-step="3"]) .ri-s3-toggle__knob {
    transform: translateX(14px);
    transition-delay: 0.8s;
  }
}

/* ═══ ri-s4 · step 5 "Step up" (agent lane: step-4) — rules below ═══ */

/* deck screen · FaceMatch1Screen "Verifying identity" choreography — the
   Selfie and ID portraits glide toward each other (±25px in the 390-wide
   user space) while the bubble tags fade just before they meet. Keyed to
   .is-active so it replays every time the step comes back around. */
@media (prefers-reduced-motion: no-preference) {
  .p-keytech-reusable-identity svg[data-sol-screen="4"].is-active .fm-face-selfie { animation: ri-s4-selfie-in 1.5s cubic-bezier(0.85, 0, 0.25, 1) 0.3s both; }
  .p-keytech-reusable-identity svg[data-sol-screen="4"].is-active .fm-face-id { animation: ri-s4-id-in 1.5s cubic-bezier(0.85, 0, 0.25, 1) 0.3s both; }
  .p-keytech-reusable-identity svg[data-sol-screen="4"].is-active .fm-tag-selfie,
  .p-keytech-reusable-identity svg[data-sol-screen="4"].is-active .fm-tag-id { animation: ri-s4-tag-out 0.4s ease 1.2s both; }
}
@keyframes ri-s4-selfie-in { from { transform: translateX(0); } to { transform: translateX(25px); } }
@keyframes ri-s4-id-in { from { transform: translateX(0); } to { transform: translateX(-25px); } }
@keyframes ri-s4-tag-out { from { opacity: 1; } to { opacity: 0; } }

/* risk-signals card (the trigger side of the story) — left of the phone,
   in the band BELOW the portrait circles so it may ride onto the phone
   without covering the circles, the heading, or the footer */
/* Camila feedback 2026-08-07: narrower card — fixed 200px, row text wraps */
.p-keytech-reusable-identity .ri-s4-card { left: 10px; top: 56%; width: 200px; max-width: calc(100% - 20px); white-space: normal; }
.p-keytech-reusable-identity .ri-s4-row { display: flex; align-items: flex-start; gap: 8px; font-size: 13px; line-height: 1.4; }
.p-keytech-reusable-identity .ri-s4-row .ri-s4-dot { margin-top: 6px; }
.p-keytech-reusable-identity .ri-s4-row--live { font-weight: 600; color: var(--color-grey-500); }
.p-keytech-reusable-identity .ri-s4-row--quiet { color: var(--color-grey-400); }
.p-keytech-reusable-identity .ri-s4-chip { flex: none; display: grid; place-items: center; width: 26px; height: 26px; border-radius: 8px; background: var(--color-grey-50); color: var(--color-grey-400); }
.p-keytech-reusable-identity .ri-s4-chip .ds-icon { width: 14px; height: 14px; }
/* ONE blue accent on this card: the live row's chip */
.p-keytech-reusable-identity .ri-s4-row--live .ri-s4-chip { background: var(--color-blue-100); color: var(--color-blue-500); }
/* the page's entire red budget: this one pulsing risk-signal dot */
.p-keytech-reusable-identity .ri-s4-dot { flex: none; width: 6px; height: 6px; margin-left: 4px; border-radius: 50%; background: var(--color-red-brand); }
@media (prefers-reduced-motion: no-preference) { .p-keytech-reusable-identity .ri-s4-dot { animation: ri-s4-pulse 2.2s ease-in-out infinite; } }
@keyframes ri-s4-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

/* verdict chip (the outcome side) — right of the phone, lower band; pops
   in only after the portraits have met (glide ends at 1.8s). Inactive or
   reduced-motion = settled visible state. */
.p-keytech-reusable-identity .ri-s4-verdict { right: 10px; top: 74%; max-width: calc(100% - 20px); flex-direction: row; align-items: center; gap: 8px; padding: 10px 14px; }
.p-keytech-reusable-identity .ri-s4-check { flex: none; display: grid; place-items: center; width: 18px; height: 18px; border-radius: 50%; background: var(--color-green-500); color: var(--color-white); }
.p-keytech-reusable-identity .ri-s4-check .ds-icon { width: 11px; height: 11px; }
@media (prefers-reduced-motion: no-preference) {
  .p-keytech-reusable-identity .sol-how:has(.sol-how__step.is-active[data-sol-step="4"]) .ri-s4-verdict { animation: ri-s4-verdict-in 0.5s cubic-bezier(0, 0.75, 0.25, 1) 1.9s both; }
}
@keyframes ri-s4-verdict-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }

/* ═══ ri-dualv · DUAL user-side phone (agent lane: dual) — rules below ═══ */
/* device bezel — mirrors the site's abstracted frame (solution.css
   .sol-stage__frame): 9px padding, hairline, radius 42 outer / 34 screen */
.p-keytech-reusable-identity .ri-dualv-phone {
  width: 100%;
  max-width: 234px;
  margin-inline: auto;
  padding: 9px;
  border-radius: 42px;
  border: 1px solid var(--color-grey-100);
  background: var(--color-white);
}
.p-keytech-reusable-identity .ri-dualv-screen {
  position: relative;
  overflow: hidden;
  border-radius: 34px;
  aspect-ratio: 390 / 844;
}
.p-keytech-reusable-identity .ri-dualv-svg { display: block; width: 100%; height: auto; }

/* ── the three flow states — stacked layers inside the screen. Base state
   (and prefers-reduced-motion) = the align/live layer only, static;
   the crossfade loop below (motion-gated) cycles all three.
   (Camila feedback ×2: tutorial layer dropped.) */
.p-keytech-reusable-identity .ri-dualv-layer { position: absolute; inset: 0; opacity: 0; }
.p-keytech-reusable-identity .ri-dualv-layer--align { opacity: 1; }

/* the live selfie video replaces the SVG's static face/scene circles */
.p-keytech-reusable-identity .ri-dualv-screen .s3-photo,
.p-keytech-reusable-identity .ri-dualv-screen .s3-scene,
.p-keytech-reusable-identity .ri-dualv-screen .s3-silhouette { display: none; }
/* only one caption at a time — keep "Align your face…", hide the
   "Get ready…" alternate (visible by default in the SVG source) */
.p-keytech-reusable-identity .ri-dualv-screen .s3-caption-ready { display: none; }
/* capture circle cx195 cy313.5 r145.5 in the 390×844 viewBox
   (percentages relative to the layer = the same box as the screen) */
.p-keytech-reusable-identity .ri-dualv-cam {
  position: absolute;
  left: 12.692%;
  top: 19.905%;
  width: 74.615%;
  height: 34.479%;
  border-radius: 50%;
  object-fit: cover;
  background: var(--color-grey-50);
}
/* the screen's own blue gradient capture ring (display:none by default)
   revealed; spins only when motion is allowed */
.p-keytech-reusable-identity .ri-dualv-screen .s3-ring-scan { display: inline; transform-box: fill-box; transform-origin: center; }
@media (prefers-reduced-motion: no-preference) {
  .p-keytech-reusable-identity .ri-dualv-screen .s3-ring-scan { animation: ri-dualv-ring-spin 2.4s linear infinite; }
}
@keyframes ri-dualv-ring-spin { to { transform: rotate(1turn); } }

/* state 2 · capturing — the ring turns green, NO caption (Camila
   feedback ×2: "changes to green without any message"): both captions
   hidden on this layer; the ring's gradient stop carries a class
   (.s3-scan-stop) so CSS retints it per instance — stop-color as a CSS
   rule beats the SVG's presentation attribute. */
.p-keytech-reusable-identity .ri-dualv-screen .ri-dualv-layer--capture .s3-caption { display: none; }
.p-keytech-reusable-identity .ri-dualv-screen .ri-dualv-layer--capture .s3-scan-stop { stop-color: var(--color-green-500); }

/* ── the loop — Camila feedback ×2: "should be faster". One 4.2s cycle,
   UNEVEN holds (align ~1.8s → green beat ~0.85s → success ~1.4s), phase
   baked into per-layer keyframes (no delays), 5%-wide crossfades landing
   exactly on the next layer's fade-in. Motion-gated: reduced motion keeps
   the base state above (align layer only, static). */
@media (prefers-reduced-motion: no-preference) {
  .p-keytech-reusable-identity .ri-dualv-layer--align { animation: ri-dualv-align 4.2s linear infinite; }
  .p-keytech-reusable-identity .ri-dualv-layer--capture { animation: ri-dualv-capture 4.2s linear infinite; }
  .p-keytech-reusable-identity .ri-dualv-layer--done { animation: ri-dualv-done 4.2s linear infinite; }
}
@keyframes ri-dualv-align {
  0% { opacity: 1; }
  42% { opacity: 1; }
  47% { opacity: 0; }
  95% { opacity: 0; }
  100% { opacity: 1; }
}
@keyframes ri-dualv-capture {
  0%, 42% { opacity: 0; }
  47% { opacity: 1; }
  62% { opacity: 1; }
  67% { opacity: 0; }
  100% { opacity: 0; }
}
@keyframes ri-dualv-done {
  0%, 62% { opacity: 0; }
  67% { opacity: 1; }
  95% { opacity: 1; }
  100% { opacity: 0; }
}

/* ═══ ri-exp · EXPERIENCE card visuals (agent lane: experience) — rules below ═══ */

/* Round 4 — match Figma "Website visuals" node 190-1776 + Camila's five
   adjustments. Uniform 320px grey-50 panels; floating white sub-cards
   (hairline + soft shadow, uppercase 11px labels); product elements
   isolated from the inline screen SVGs via fixed crop windows.
   Card ↔ ph map (data keys kept greppable):
   01 (v2) the Selfie3 capture unit LIVE — selfie video clipped into the
      photo circle UNDER the silhouette + the blue gradient ring
      spinning; no chip.
   02 (v3) smaller capture unit upper-left, ring re-tinted GREEN
      (capture complete) + dashed elbow into "Identity reusability".
   03 (v4) consent card — ONE blue checkbox (the accent) + a quiet
      hairline-divided list of what the user shares.
   04 (v5) FaceMatch1 portrait pair + "Selfie"/"Face on file" pill
      tooltips + the "On device" card w/ the canonical 16px spinner.
   05 (v6) "Risk signal" card (8px amber dot — the page's only yellow)
      overlapping the site's own license art in a blue capture frame.
   .ri-exp-iso  = positioner (+ soft element drop shadow);
   .ri-exp-fig  = fixed-size crop window; the 390×844 SVG inside is
   scaled/offset per variant so the target element fills the window.
   Geometry sources: Selfie3 capture unit 335×335 at (27.5,146), center
   195/313.5, photo r 145.5, ring outer r 167.5 · FaceMatch1 portraits
   r 80 at cx 107.5 / 282.5, cy 360. All motion gated behind
   prefers-reduced-motion: no-preference with settled fallbacks. */
.p-keytech-reusable-identity .ri-exp-iso {
  position: absolute; left: 50%; transform: translateX(-50%);
}
.p-keytech-reusable-identity .ri-exp-fig { position: relative; overflow: hidden; }
/* max-width: none — base.css clamps every svg to 100% of its container,
   which would silently re-scale the oversized crop SVG to the window
   width and shear the whole composition off its computed offsets */
.p-keytech-reusable-identity .ri-exp-fig .ri-exp-svg { position: absolute; display: block; height: auto; max-width: none; }

/* the 5-up grid squeezes the panels below the compositions' natural
   width at the narrow end of each band (panel ≈ 164px at 1120 ·
   ≈ 196px at 1280 · ≥ 224px from ~1430). Scale the whole mock layer
   about its center so every composition keeps its geometry and simply
   breathes down to fit. */
@media (min-width: 1120px) and (max-width: 1279.98px) {
  .p-keytech-reusable-identity .dv-cap__viz .ri-mock { transform: scale(0.72); }
}
@media (min-width: 1280px) and (max-width: 1429.98px) {
  .p-keytech-reusable-identity .dv-cap__viz .ri-mock { transform: scale(0.86); }
}

/* kill every screen-chrome layer + the unclassed white ground rect
   (first child of the SVG's top-level group) — only the isolated
   product elements may render */
.p-keytech-reusable-identity .ri-exp-svg > g > rect:first-child,
.p-keytech-reusable-identity .ri-exp-svg .s3-status,
.p-keytech-reusable-identity .ri-exp-svg .s3-wordmark,
.p-keytech-reusable-identity .ri-exp-svg .s3-caption,
.p-keytech-reusable-identity .ri-exp-svg .s3-caption-ready,
.p-keytech-reusable-identity .ri-exp-svg .s3-ring-scan,
.p-keytech-reusable-identity .ri-exp-svg .s3-verified,
.p-keytech-reusable-identity .ri-exp-svg .s3-home { display: none; }

/* card 01 (ph v2) — the full capture unit (grey track + silhouette +
   blue gradient ring) at 200px, LIVE: the selfie video sits UNDER the
   SVG (DOM order), clipped to the photo circle, so the silhouette and
   rings paint over it. Scale s = 200/335 = 0.5970:
   svg w = 390s = 232.8 · left = −27.5s = −16.4 · top = −146s = −87.2.
   Video (photo circle r 145.5): size = 291s = 173.7, inset = 22s = 13.1.
   The ring spins while motion is allowed; reduced motion = static ring
   over the (browser-stilled or looping) feed. */
.p-keytech-reusable-identity .ri-exp-iso--v2 { top: 60px; }
.p-keytech-reusable-identity .ri-exp-fig--v2 { width: 200px; height: 200px; clip-path: circle(50%); }
.p-keytech-reusable-identity .ri-exp-fig--v2 .ri-exp-svg { width: 232.8px; left: -16.4px; top: -87.2px; }
.p-keytech-reusable-identity .ri-exp-fig--v2 .s3-photo,
.p-keytech-reusable-identity .ri-exp-fig--v2 .s3-scene,
.p-keytech-reusable-identity .ri-exp-fig--v2 .s3-silhouette { display: none; } /* designer round 2: just the live face — no silhouette vector over the video */
.p-keytech-reusable-identity .ri-exp-cam {
  position: absolute; left: 13.1px; top: 13.1px; width: 173.7px; height: 173.7px;
  border-radius: 50%; object-fit: cover; background: var(--color-grey-50);
}
.p-keytech-reusable-identity .ri-exp-fig--v2 .s3-ring-scan { display: inline; transform-box: fill-box; transform-origin: center; }
@media (prefers-reduced-motion: no-preference) {
  .p-keytech-reusable-identity .ri-exp-fig--v2 .s3-ring-scan { animation: ri-exp-ring-spin 2.4s linear infinite; }
}
@keyframes ri-exp-ring-spin { to { transform: rotate(1turn); } }

/* card 02 (ph v3) — the capture unit again at 116px, static photo kept,
   ring revealed NOT spinning and re-tinted green via the gradient stop
   (CSS stop-color beats the presentation attribute) = the real
   capture-complete state. Scale s = 116/335 = 0.3463: svg w = 135 ·
   left = −27.5s = −9.5 · top = −146s = −50.6. The cluster (circle +
   elbow + card) is anchored off panel-center so it composes the same
   at every panel width: circle left = 50% − 78px → its right edge at
   50% + 38px, where the dashed elbow starts and runs 40px over +
   120px down onto the card's top edge. */
.p-keytech-reusable-identity .ri-exp-iso--v3 { left: calc(50% - 78px); transform: none; top: 30px; }
.p-keytech-reusable-identity .ri-exp-fig--v3 { width: 116px; height: 116px; clip-path: circle(50%); }
.p-keytech-reusable-identity .ri-exp-fig--v3 .ri-exp-svg { width: 135px; left: -9.5px; top: -50.6px; }
.p-keytech-reusable-identity .ri-exp-fig--v3 .s3-ring-scan { display: inline; }
.p-keytech-reusable-identity .ri-exp-fig--v3 .s3-scan-stop { stop-color: var(--color-green-500); }
.p-keytech-reusable-identity .ri-exp-elbow {
  position: absolute; left: calc(50% + 38px); top: 88px; width: 40px; height: 116px;
  border-top: 1.5px dashed var(--color-grey-300);
  border-right: 1.5px dashed var(--color-grey-300);
  border-top-right-radius: 12px;
}
/* the card itself (--reuse) is positioned with the shared card rules
   below — variant position overrides must sit AFTER the base rule or
   the base's bottom/left/transform win at equal specificity */

/* card 04 (ph v5) — the portrait pair as two plain 100px circular imgs
   (designer round 2: the right circle is a DIFFERENT SELFIE of the same
   person — face-match-1-selfie.webp left, the Selfie3 face photo right;
   on disk the woman lives in selfie-3-SCENE.webp, see the markup note).
   HTML pill tooltips above each circle; on reveal the pair glides
   together; reduced motion renders settled. Circle centers x 50 / 159
   inside the 209px pair. */
.p-keytech-reusable-identity .ri-exp-iso--v5 { top: 84px; }
.p-keytech-reusable-identity .ri-exp-pair { display: flex; gap: 9px; }
/* .ri-exp-pair in the selector so this outranks the template's
   `.p-document-verification .dv-cap__viz img` sizing (the body carries
   both page classes; that rule's extra type selector beats a bare
   two-class selector) */
.p-keytech-reusable-identity .ri-exp-pair .ri-exp-face {
  width: 100px; height: 100px; border-radius: 50%;
  object-fit: cover; flex: 0 0 auto;
  background: var(--color-grey-50);
}
@media (prefers-reduced-motion: no-preference) {
  .p-keytech-reusable-identity .ri-exp-face { transition: transform 1s var(--ease-out-expo) 0.25s; }
  .p-keytech-reusable-identity .dv-capture__grid:not(.is-revealed) .ri-exp-face { transform: translateX(-12px); }
  .p-keytech-reusable-identity .dv-capture__grid:not(.is-revealed) .ri-exp-face--file { transform: translateX(12px); }
}
.p-keytech-reusable-identity .ri-exp-tip {
  position: absolute; top: -36px; transform: translateX(-50%);
  padding: 5px 11px; border-radius: 999px; white-space: nowrap;
  border: 1px solid var(--color-border-light); background: var(--color-white);
  box-shadow: none;
  font-family: var(--font-sans); font-size: 11px; font-weight: 500; color: var(--color-grey-500);
}
.p-keytech-reusable-identity .ri-exp-tip--selfie { left: 50px; }
.p-keytech-reusable-identity .ri-exp-tip--id { left: 159px; }

/* card 05 (ph v6) — the site's own license art (700×440 webp, crisp at
   panel width) wrapped in the blue capture-frame look; the risk card
   overlaps its top edge (z-index above). */
.p-keytech-reusable-identity .ri-exp-lic {
  position: absolute; left: 50%; top: 116px; transform: translateX(-50%);
  width: 200px; padding: 3px; border-radius: 14px;
  border: 2px solid var(--color-blue-500); background: var(--color-white);
  box-shadow: none;
}
.p-keytech-reusable-identity .ri-exp-lic img { display: block; width: 100%; height: auto; border-radius: 9px; }
/* the risk card (--risk) is positioned with the shared card rules below */
.p-keytech-reusable-identity .ri-exp-dot {
  width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto;
  background: var(--color-yellow-500);
}

/* --- the floating white sub-card — ONE shared style across all five
   panels (white, radius 12–14, hairline + soft shadow, stacked
   uppercase 11px label), per the section's card idiom --- */
.p-keytech-reusable-identity .ri-exp-card {
  position: absolute; z-index: 2; left: 50%; bottom: 14px; transform: translateX(-50%);
  display: flex; flex-direction: column; gap: 6px; padding: 10px 13px;
  border: 1px solid var(--color-border-light); border-radius: 12px;
  background: var(--color-white);
  box-shadow: none;
  font-family: var(--font-sans); white-space: nowrap;
}
.p-keytech-reusable-identity .ri-exp-label {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--color-grey-400);
}
.p-keytech-reusable-identity .ri-exp-row {
  display: flex; align-items: center; gap: 8px;
  font-size: var(--fs-xs); font-weight: 500; color: var(--color-grey-500);
}
/* the resolved check — solid green ≥18px circle, CSS-drawn white check */
.p-keytech-reusable-identity .ri-exp-ok {
  width: 18px; height: 18px; border-radius: 50%; flex: 0 0 auto;
  display: grid; place-items: center;
  background: var(--color-green-500);
}
.p-keytech-reusable-identity .ri-exp-ok::after,
.p-keytech-reusable-identity .ri-exp-cb::after {
  content: ""; width: 8px; height: 4.5px; margin-top: -2px;
  border-left: 1.6px solid var(--color-white);
  border-bottom: 1.6px solid var(--color-white);
  transform: rotate(-45deg);
}
/* small grey glyph slot (share-list rows + the label's device glyph) */
.p-keytech-reusable-identity .ri-exp-ic { width: 16px; height: 16px; flex: 0 0 auto; display: grid; place-items: center; color: var(--color-grey-400); }
.p-keytech-reusable-identity .ri-exp-ic .ds-icon { width: 14px; height: 14px; }
.p-keytech-reusable-identity .ri-exp-label .ri-exp-ic { width: 14px; height: 14px; }
.p-keytech-reusable-identity .ri-exp-label .ri-exp-ic .ds-icon { width: 12px; height: 12px; }

/* card 03 (ph v4) — the consent card centered on the panel; the
   checkbox row is the ONLY accent, the share list below stays quiet */
.p-keytech-reusable-identity .ri-exp-card--consent {
  bottom: auto; top: 50%; transform: translate(-50%, -50%);
  padding: 13px 15px; gap: 10px; border-radius: 14px;
}
.p-keytech-reusable-identity .ri-exp-consent {
  display: flex; align-items: center; gap: 9px;
  font-size: var(--fs-xs); font-weight: 600; color: var(--color-grey-500);
}
.p-keytech-reusable-identity .ri-exp-cb {
  width: 18px; height: 18px; border-radius: 5px; flex: 0 0 auto;
  display: grid; place-items: center;
  background: var(--color-blue-500);
}
.p-keytech-reusable-identity .ri-exp-share {
  display: flex; flex-direction: column; gap: 7px;
  padding-top: 10px; border-top: 1px solid var(--color-grey-100);
}

/* variant positions — AFTER the base rule so they win the cascade at
   equal specificity. card 02's reuse card is a touch larger (designer
   round 2) so the elbow visibly lands on its top edge — the elbow's
   116px drop from y88 ends at y204, 4px INSIDE the enlarged card's top
   (≈ y200 at bottom 36); the card paints over the overlap (z2 vs auto)
   so the dashed line reads as meeting the edge. card 04's device card
   gets extra clearance; card 05's risk card is centered horizontally
   (designer round 2), still overlapping the license's top edge. */
.p-keytech-reusable-identity .ri-exp-card--reuse {
  left: calc(50% - 88px); transform: none; bottom: 36px;
  padding: 12px 15px; gap: 7px; min-width: 184px;
}
.p-keytech-reusable-identity .ri-exp-card--device { bottom: 22px; }
.p-keytech-reusable-identity .ri-exp-card--risk { bottom: auto; top: 66px; z-index: 3; }

/* the canonical 16px spinner (blue track + arc), motion-gated */
.p-keytech-reusable-identity .ri-exp-spin { width: 16px; height: 16px; flex: none; }
.p-keytech-reusable-identity .ri-exp-spin-track { stroke: var(--color-blue-100); }
.p-keytech-reusable-identity .ri-exp-spin-arc { stroke: var(--color-blue-500); stroke-linecap: round; stroke-dasharray: 30 70; }
@media (prefers-reduced-motion: no-preference) {
  .p-keytech-reusable-identity .ri-exp-spin { animation: ri-exp-spin 0.9s linear infinite; }
}
@keyframes ri-exp-spin { to { transform: rotate(1turn); } }

/* ═══ ri-privx · PRIVACY abstract visual (agent lane: privacy) — rules below ═══ */

/* ── PRIVACY section shell (QA 2026-08-08): upstream #1256's sweep DELETED
   the light .dv-global block from document-verification.css (that page's
   section went dark), which left THIS page's clone-swapped privacy section
   unstyled — black-on-black title, no grid, plain-text stats. Restored
   here verbatim from the deleted template rules, page-scoped (the extra
   .p-keytech class outranks the template's new dark rules). ── */
.p-document-verification.p-keytech-reusable-identity .dv-global { background: var(--color-background); border-top: 1px solid var(--color-border-light); }
.p-document-verification.p-keytech-reusable-identity .dv-global__grid { display: grid; gap: 48px; }
@media (min-width: 1024px) { .p-document-verification.p-keytech-reusable-identity .dv-global__grid { grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr); gap: 64px; align-items: start; } }
.p-document-verification.p-keytech-reusable-identity .dv-global .section-title { color: var(--color-black); }
.p-document-verification.p-keytech-reusable-identity .dv-global .kicker { color: var(--color-kicker-on-white); }
.p-document-verification.p-keytech-reusable-identity .dv-global__copy .dv-intro { color: var(--color-grey-on-white); }
.p-document-verification.p-keytech-reusable-identity .dv-global__points { margin-top: 28px; display: flex; flex-direction: column; gap: 20px; }
.p-document-verification.p-keytech-reusable-identity .dv-global__point { display: grid; grid-template-columns: auto 1fr; gap: 14px; border: 0; border-radius: 0; background: none; padding: 0; /* the template's 2026-08-13 dark chip box stays off this light clone */ }
.p-document-verification.p-keytech-reusable-identity .dv-global__icon { width: 38px; height: 38px; border-radius: var(--radius-md); display: grid; place-items: center; background: var(--color-blue-100); color: var(--color-blue-500); }
.p-document-verification.p-keytech-reusable-identity .dv-global__name { display: block; font-family: var(--font-display); font-weight: 500; font-size: var(--fs-xl); color: var(--color-black); }
.p-document-verification.p-keytech-reusable-identity .dv-global__line { display: block; margin-top: 3px; font-size: var(--fs-sm); line-height: 1.55; color: var(--color-grey-on-white); }
.p-document-verification.p-keytech-reusable-identity .dv-global__big { margin-top: 36px; display: flex; gap: 56px; flex-wrap: wrap; }
.p-document-verification.p-keytech-reusable-identity .dv-global__bigstat .stat-grad { font-family: var(--font-display); font-weight: 500; letter-spacing: var(--track-tighter); font-size: clamp(38px, 5vw, 52px); }
.p-document-verification.p-keytech-reusable-identity .dv-global__bigcap { margin-top: 4px; font-size: var(--fs-sm); color: var(--color-grey-on-white); }
.p-document-verification.p-keytech-reusable-identity .dv-global__map { position: relative; width: 100%; }

/* ── reduced-motion patch (QA 2026-08-08, LOW): the shared template's
   static-mode fill animation outspecifies its own reduce override
   (solution.css:637 vs :645) — kill it page-scoped so the #how walk's
   underline holds still under reduce. ── */
@media (prefers-reduced-motion: reduce) {
  .p-keytech-reusable-identity .sol-flow-wrap:not(.is-float) .sol-how__step.is-active .sol-how__fill { animation: none; }
}

/* final abstract art for §6 privacy — "reused as proof, never as data".
   White card + hairline like the mock it replaces; inside, a tokens-only
   SVG scene: sealed identity core (rings + keyed token) in the user's
   domain, redacted PII locked behind the boundary, and the single blue
   proof token crossing the gate to the relying business. */
/* option F · flat layers (Camila pick 2026-08-08 — playground round 2).
   The site's hero-illustration grammar: flat token fills, no outlines,
   one blue element, depth by overlap, bare on the section ground.
   Ambient: the three layers float slowly, staggered (the industry-hero
   ambient); reduced motion = still. (The previous ri-privx drawing was
   replaced wholesale — same lane, same pass.) */
.p-keytech-reusable-identity .ri-privf { width: 100%; max-width: 480px; margin-inline: auto; }
.p-keytech-reusable-identity .ri-privf__svg { display: block; width: 100%; height: auto; }
.p-keytech-reusable-identity .ri-privf-sheet { fill: var(--color-grey-100); }
.p-keytech-reusable-identity .ri-privf-bar { fill: var(--color-grey-200); }
.p-keytech-reusable-identity .ri-privf-panel { fill: var(--color-grey-200); }
.p-keytech-reusable-identity .ri-privf-lock { fill: var(--color-grey-400); }
.p-keytech-reusable-identity .ri-privf-shackle { fill: none; stroke: var(--color-grey-400); }
.p-keytech-reusable-identity .ri-privf-card { fill: var(--color-blue-500); }
.p-keytech-reusable-identity .ri-privf-check { fill: var(--color-white); }
.p-keytech-reusable-identity .ri-privf-tick { fill: none; stroke: var(--color-blue-500); }
.p-keytech-reusable-identity .ri-privf-line { fill: color-mix(in oklab, var(--color-white) 82%, transparent); }
@media (prefers-reduced-motion: no-preference) {
  .p-keytech-reusable-identity .ri-privf-layer { animation: ri-privf-float 7s ease-in-out infinite; }
  .p-keytech-reusable-identity .ri-privf-layer--seal { animation-duration: 8.2s; animation-delay: -2s; }
  .p-keytech-reusable-identity .ri-privf-layer--proof { animation-duration: 6.4s; animation-delay: -4s; }
}
@keyframes ri-privf-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-6px); }
}
  50% { transform: scale(1.035); opacity: 0.55; }
}
