> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.idenfy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Standalone Bank Card Verification

> How the standalone iDenfy bank card check works: the consent and capture screens, what spends a retry attempt, the two session clocks, and the results your end user sees.

export const SceneRow = ({children}) => <div className="iuk iuk-row">{children}</div>;

export const Scene = ({label, dim, tone, callout, children}) => <div className="iuk iuk-col">
    {label ? <div className="iuk-cap">
        {tone === "ok" || tone === "no" ? <span className={`iuk-tag${tone === "no" ? " iuk-tag-no" : ""}`}>{label}</span> : <span className="iuk-cap-label">{label}</span>}
        {dim ? <span className="iuk-dim">{dim}</span> : null}
      </div> : null}
    {children}
    {callout ? <span className={`iuk-callout iuk-callout-${tone === "no" ? "no" : tone === "ok" ? "ok" : "info"}`}>{callout}</span> : null}
  </div>;

export const ResultIcon = ({tone = "success"}) => <div className={`iuk iuk-result iuk-result-${tone}`}>
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      {tone === "success" ? <><circle cx="12" cy="12" r="9" /><path d="M8 12.4l2.8 2.8L16 9.6" /></> : tone === "danger" ? <><circle cx="12" cy="12" r="9" /><path d="M12 7.5v5M12 16v.6" /></> : <><path d="M12 4l8.5 15H3.5L12 4z" /><path d="M12 10v4M12 16.6v.6" /></>}
    </svg>
  </div>;

export const InfoField = ({children}) => <div className="iuk iuk-infofield">
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <circle cx="12" cy="12" r="9" />
      <path d="M8 12.4l2.8 2.8L16 9.6" />
    </svg>
    <span className="iuk-infofield-text">{children}</span>
  </div>;

export const ShutterBar = ({shutter = "on", left = true, right = true}) => <div className="iuk iuk-shutterbar">
    <span className="iuk-shutterbar-side">
      {left ? <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
          <path d="M4 8.5A2 2 0 016 6.5h2l1.2-2h5.6L16 6.5h2a2 2 0 012 2v8a2 2 0 01-2 2H6a2 2 0 01-2-2v-8z" />
          <path d="M9.5 12.5h5M12.8 10.6l1.9 1.9-1.9 1.9" />
        </svg> : null}
    </span>
    <span className={`iuk-shutter-btn${shutter === "off" ? " iuk-shutter-off" : ""}`} />
    <span className="iuk-shutterbar-side">
      {right ? <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
          <path d="M12 16V4M7.5 8.5L12 4l4.5 4.5M4 17v2a2 2 0 002 2h12a2 2 0 002-2v-2" />
        </svg> : null}
    </span>
  </div>;

export const Modal = ({title, message, tone = "warning", footer, children}) => {
  const art = {
    warning: <><path d="M12 4l8.5 15H3.5L12 4z" /><path d="M12 10v4M12 16.6v.6" /></>,
    danger: <><circle cx="12" cy="12" r="9" /><path d="M12 7.5v5M12 16v.6" /></>,
    info: <><circle cx="12" cy="12" r="9" /><path d="M12 11v5M12 7.6v.6" /></>
  };
  const colour = tone === "danger" ? "#e91b0c" : tone === "info" ? "#1e7afd" : "#ff9800";
  return <div className="iuk iuk-modalwrap">
      <div className="iuk-modal">
        {title ? <div className="iuk-modal-head">
            <span className="iuk-modal-title">{title}</span>
          </div> : null}
        <div className="iuk-modal-body">
          <div className="iuk-modal-panel">
            <div className="iuk-modal-art">
              <svg viewBox="0 0 24 24" fill="none" stroke={colour} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                {art[tone] || art.warning}
              </svg>
            </div>
            {message ? <span className="iuk-modal-msg">{message}</span> : null}
            {children}
          </div>
        </div>
        {footer ? <div className="iuk-modal-foot">{footer}</div> : null}
      </div>
    </div>;
};

export const MaskedCard = ({last4, expiry, state}) => <div className={`iuk iuk-maskedcard${state === "active" ? " iuk-maskedcard-active" : ""}`}>
    <span className="iuk-maskedcard-num">{`•••• ${last4}`}</span>
    {expiry ? <span className="iuk-maskedcard-exp">{expiry}</span> : null}
  </div>;

export const DeviceHandoff = ({sms = true, inApp = false, escape: escapeText}) => <div className="iuk iuk-handoff">
    <span className="iuk-qr"><svg viewBox="0 0 21 21" fill="currentColor" aria-hidden="true"><path d="M0 0h7v1h-7zM9 0h1v1h-1zM11 0h2v1h-2zM14 0h7v1h-7zM0 1h1v1h-1zM6 1h1v1h-1zM9 1h1v1h-1zM14 1h1v1h-1zM20 1h1v1h-1zM0 2h1v1h-1zM2 2h3v1h-3zM6 2h1v1h-1zM8 2h1v1h-1zM10 2h1v1h-1zM12 2h1v1h-1zM14 2h1v1h-1zM16 2h3v1h-3zM20 2h1v1h-1zM0 3h1v1h-1zM2 3h3v1h-3zM6 3h1v1h-1zM10 3h1v1h-1zM14 3h1v1h-1zM16 3h3v1h-3zM20 3h1v1h-1zM0 4h1v1h-1zM2 4h3v1h-3zM6 4h1v1h-1zM8 4h2v1h-2zM14 4h1v1h-1zM16 4h3v1h-3zM20 4h1v1h-1zM0 5h1v1h-1zM6 5h1v1h-1zM8 5h1v1h-1zM10 5h2v1h-2zM14 5h1v1h-1zM20 5h1v1h-1zM0 6h7v1h-7zM8 6h1v1h-1zM10 6h1v1h-1zM12 6h1v1h-1zM14 6h7v1h-7zM9 7h1v1h-1zM0 8h1v1h-1zM4 8h1v1h-1zM6 8h1v1h-1zM11 8h1v1h-1zM15 8h2v1h-2zM18 8h2v1h-2zM3 9h1v1h-1zM5 9h1v1h-1zM7 9h1v1h-1zM12 9h3v1h-3zM16 9h1v1h-1zM18 9h1v1h-1zM0 10h1v1h-1zM4 10h4v1h-4zM13 10h1v1h-1zM15 10h1v1h-1zM17 10h3v1h-3zM3 11h2v1h-2zM7 11h1v1h-1zM11 11h2v1h-2zM14 11h3v1h-3zM3 12h1v1h-1zM5 12h2v1h-2zM9 12h1v1h-1zM12 12h1v1h-1zM18 12h1v1h-1zM20 12h1v1h-1zM9 13h2v1h-2zM13 13h1v1h-1zM20 13h1v1h-1zM0 14h7v1h-7zM12 14h2v1h-2zM15 14h1v1h-1zM17 14h2v1h-2zM20 14h1v1h-1zM0 15h1v1h-1zM6 15h1v1h-1zM8 15h4v1h-4zM13 15h1v1h-1zM17 15h3v1h-3zM0 16h1v1h-1zM2 16h3v1h-3zM6 16h1v1h-1zM8 16h1v1h-1zM10 16h1v1h-1zM13 16h1v1h-1zM18 16h3v1h-3zM0 17h1v1h-1zM2 17h3v1h-3zM6 17h1v1h-1zM8 17h2v1h-2zM12 17h4v1h-4zM18 17h1v1h-1zM0 18h1v1h-1zM2 18h3v1h-3zM6 18h1v1h-1zM8 18h1v1h-1zM11 18h2v1h-2zM14 18h3v1h-3zM0 19h1v1h-1zM6 19h1v1h-1zM8 19h2v1h-2zM12 19h2v1h-2zM16 19h2v1h-2zM19 19h1v1h-1zM0 20h7v1h-7zM8 20h1v1h-1zM10 20h1v1h-1zM12 20h1v1h-1zM16 20h2v1h-2z" /></svg></span>
    {sms ? <>
        <span className="iuk-handoff-or">or</span>
        <div className="iuk-field" style={{
  width: "100%"
}}>
          <div className="iuk-field-box">
            <span className="iuk-field-ph">+370 600 00000</span>
          </div>
          <span className="iuk-field-label">Phone number</span>
        </div>
        <span className="iuk-btn iuk-btn-outlined">Send SMS link</span>
      </> : null}
    {inApp ? <span className="iuk-btn iuk-btn-outlined">Continue in app</span> : null}
    {escapeText ? <span className="iuk-handoff-escape">{escapeText}</span> : null}
  </div>;

export const FilePreview = ({name, meta}) => <div className="iuk iuk-filerow">
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <path d="M13.5 3H7a2 2 0 00-2 2v14a2 2 0 002 2h10a2 2 0 002-2V8.5L13.5 3z" />
      <path d="M13.5 3v5.5H19" />
    </svg>
    <span style={{
  minWidth: 0
}}>
      <span className="iuk-filerow-name">{name}</span>
      {meta ? <span className="iuk-filerow-meta">{meta}</span> : null}
    </span>
  </div>;

export const UploadBox = ({prompt, trigger, hint, state}) => <div className={`iuk iuk-upload${state === "drag" ? " iuk-upload-drag" : ""}`}>
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <path d="M12 16V4M7.5 8.5L12 4l4.5 4.5M4 17v2a2 2 0 002 2h12a2 2 0 002-2v-2" />
    </svg>
    <span className="iuk-upload-prompt">
      {prompt}
      {trigger ? <> <span className="iuk-upload-trigger">{trigger}</span></> : null}
    </span>
    {hint ? <span className="iuk-upload-hint">{hint}</span> : null}
  </div>;

export const Assurances = ({items = []}) => {
  const glyphs = [<><rect x="4.5" y="10.5" width="15" height="10" rx="2" /><path d="M8 10.5V7.5a4 4 0 018 0v3" /></>, <><path d="M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6z" /><circle cx="12" cy="12" r="2.8" /></>, <><circle cx="12" cy="12" r="9" /><path d="M8 12.4l2.8 2.8L16 9.6" /></>, <><path d="M12 3l7.5 3v6c0 4.2-3 7.6-7.5 9-4.5-1.4-7.5-4.8-7.5-9V6L12 3z" /><path d="M9 12.2l2.2 2.2L15 10.6" /></>];
  return <div className="iuk iuk-assurances">
      {items.map((t, i) => <div className="iuk-assurance" key={i}>
          <span className="iuk-assurance-chip">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
              {glyphs[i % glyphs.length]}
            </svg>
          </span>
          <span className="iuk-assurance-text">{t}</span>
        </div>)}
    </div>;
};

export const DocCard = ({title, desc, icon, state}) => {
  const glyphs = {
    card: <path d="M2.5 10h19M6 15h3" />,
    document: <path d="M7.5 9h4M7.5 13h9M7.5 16.5h6" />,
    camera: <circle cx="12" cy="13" r="3.4" />,
    lock: <path d="M8 10.5V7.5a4 4 0 018 0v3" />
  };
  const shells = {
    card: <rect x="2.5" y="5" width="19" height="14" rx="2.5" />,
    document: <rect x="3.5" y="4" width="17" height="16" rx="2" />,
    camera: <path d="M3 8.5A2 2 0 015 6.5h2l1.2-2h7.6L17 6.5h2a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2v-9z" />,
    lock: <rect x="4.5" y="10.5" width="15" height="10" rx="2" />
  };
  return <div className={`iuk iuk-doccard${state === "active" ? " iuk-doccard-active" : state === "hover" ? " iuk-doccard-hover" : ""}`}>
      {icon && shells[icon] ? <span className="iuk-doccard-icon">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            {shells[icon]}
            {glyphs[icon]}
          </svg>
        </span> : null}
      <span>
        <span className="iuk-doccard-title">{title}</span>
        {desc ? <span className="iuk-doccard-desc">{desc}</span> : null}
      </span>
    </div>;
};

export const CameraFrame = ({ratio = "4/3", overlay = "document", state = "idle", hint, shutter = false, scrim, children}) => <div className={`iuk iuk-cam ${ratio === "16/9" ? "iuk-cam-169" : "iuk-cam-43"} iuk-cam-${state}`}>
    {overlay === "document" ? <>
        <div className="iuk-cam-center">
          <span className="iuk-idcard">
            <span className="iuk-idcard-photo" />
            <span className="iuk-idcard-lines" />
            <span className="iuk-idcard-mrz" />
          </span>
        </div>
        <div className="iuk-cam-window" />
        <div className="iuk-cam-corners">
          <span className="iuk-cam-corner iuk-cam-corner-tl" />
          <span className="iuk-cam-corner iuk-cam-corner-tr" />
          <span className="iuk-cam-corner iuk-cam-corner-bl" />
          <span className="iuk-cam-corner iuk-cam-corner-br" />
        </div>
      </> : null}
    {overlay === "card" ? <>
        <div className="iuk-cam-center">
          <span className="iuk-bankcard">
            <span className="iuk-bankcard-chip" />
            <span className="iuk-bankcard-num"><span /><span /><span /><span /></span>
            <span className="iuk-bankcard-name" />
            <span className="iuk-bankcard-brand" />
          </span>
        </div>
        <div className="iuk-cam-window-card" />
        <div className="iuk-cam-corners-card">
          <span className="iuk-cam-corner iuk-cam-corner-tl" />
          <span className="iuk-cam-corner iuk-cam-corner-tr" />
          <span className="iuk-cam-corner iuk-cam-corner-bl" />
          <span className="iuk-cam-corner iuk-cam-corner-br" />
        </div>
      </> : null}
    {overlay === "face" ? <>
        <div className="iuk-cam-oval" />
        <div className="iuk-cam-ring" />
      </> : null}
    {overlay === "upload" ? <div className="iuk-cam-upload">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
          <path d="M12 16V4M7.5 8.5L12 4l4.5 4.5M4 17v2a2 2 0 002 2h12a2 2 0 002-2v-2" />
        </svg>
        <span className="iuk-cam-upload-lbl">Upload a file</span>
      </div> : null}
    {children}
    {hint ? <span className="iuk-cam-hint">{hint}</span> : null}
    {shutter ? <span className="iuk-cam-shutter" /> : null}
    {scrim ? <div className="iuk-cam-scrim">{scrim}</div> : null}
  </div>;

export const Timer = ({value = "29:32"}) => <span className="iuk iuk-timer">
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <circle cx="12" cy="12" r="9" />
      <path d="M12 7.5V12l3.2 2" />
    </svg>
    <span className="iuk-timer-val">{value}</span>
  </span>;

export const Text = ({size, children}) => <p className={`iuk ${size === "fine" ? "iuk-fine" : "iuk-p"}`}>{children}</p>;

export const Btn = ({variant = "filled", state, children}) => {
  const cls = variant === "link" ? `iuk-btn-link${state === "disabled" ? " iuk-btn-link-disabled" : ""}` : `iuk-btn iuk-btn-${state === "disabled" ? "disabled" : state === "hover" ? "hover" : variant}`;
  return <span className={`iuk ${cls}`}>{children}</span>;
};

export const IdvCard = ({title, sub, footer, fluid = false, children}) => <div className={`iuk iuk-card${fluid ? " iuk-card-fluid" : ""}`}>
    {title ? <h4 className="iuk-h1">{title}</h4> : null}
    {sub ? <p className="iuk-sub">{sub}</p> : null}
    {children ? <div className="iuk-card-body">{children}</div> : null}
    {footer ? <div className="iuk-actions">{footer}</div> : null}
  </div>;

export const IdvShell = ({lang = "EN", back = false, footer = true, flush = false, children}) => <div className={`iuk iuk-shell${flush ? " iuk-shell-flush" : ""}`}>
    <div className="iuk-topbar">
      <span className="iuk-topbar-slot">{back ? <span className="iuk-chip">←</span> : null}</span>
      <span className="iuk-logo">iDenfy</span>
      <span className="iuk-topbar-slot iuk-topbar-slot-end">
        {lang ? <span className="iuk-chip">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
              <circle cx="12" cy="12" r="9" />
              <path d="M3 12h18M12 3c2.5 3 2.5 15 0 18M12 3c-2.5 3-2.5 15 0 18" />
            </svg>
            {lang}
          </span> : null}
      </span>
    </div>
    {children}
    {footer ? <div className="iuk-footer">
        © iDenfy™, 2026. All rights reserved. <span className="iuk-footer-link">Privacy policy</span>
      </div> : null}
  </div>;

export const UiKitStyles = () => {
  const css = `
/* ---------- product tokens, inlined as literals (must not flip) ----------
   purple #734bfb  hover #452d97  tint #efebff
   ink #19181d  muted #6f7486  border #d8dee9
   surface #fff  page #f7f8fa  hover-tint #f2f4f8  subtle #e6e9ef
   disabled-bg #eaeaeb  disabled-fg #c0c0c3
   success #00c853/#e8f5e9  error #e91b0c/#ffebee
   warning #ff9800/#fff3e0  info #1e7afd/#e9f2ff
   ------------------------------------------------------------------------ */

.iuk, .iuk * { box-sizing: border-box; }
.iuk {
  font-family: inherit;
  -webkit-font-smoothing: antialiased;
}

/* ========================= DOCS CHROME ================================== */


/* Row of side-by-side scenes, reflows with no media queries */
.iuk-row {
  display: flex;
  gap: 20px;
  align-items: stretch;
  flex-wrap: wrap;
  margin: 1.5rem 0;
}
.iuk-col { flex: 1 1 260px; min-width: 0; display: flex; flex-direction: column; gap: 10px; }

/* Caption above a scene: label left, dimension right */
.iuk-cap { display: flex; justify-content: space-between; align-items: center; gap: 8px; padding: 0 2px; }
.iuk-cap-label {
  font-weight: 700; font-size: 13px; line-height: 1.3;
  color: rgb(var(--gray-800));
}
.dark .iuk-cap-label { color: rgb(var(--gray-200)); }

/* Do / Don't tag with a status dot */
.iuk-tag {
  display: inline-flex; align-items: center; gap: 8px;
  font-weight: 700; font-size: 13px; line-height: 1.3;
  color: #3f7741;
}
.iuk-tag::before {
  content: ""; width: 10px; height: 10px; border-radius: 50%;
  background: #60a561; box-shadow: 0 0 0 3px rgb(96 165 97 / 0.22);
}
.iuk-tag-no { color: #b82f4f; }
.iuk-tag-no::before { background: #da4167; box-shadow: 0 0 0 3px rgb(218 65 103 / 0.22); }
.dark .iuk-tag { color: #7bcb7d; }
.dark .iuk-tag-no { color: #f17a99; }

/* Mono dimension / spec label */
.iuk-dim {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-weight: 600; font-size: 12px; letter-spacing: 0.06em;
  color: rgb(var(--gray-500));
  white-space: nowrap;
}
.dark .iuk-dim { color: rgb(var(--gray-400)); }

/* Uppercase verdict pill under a scene */
.iuk-callout {
  align-self: flex-start;
  font-weight: 700; font-size: 10px; letter-spacing: 0.04em;
  text-transform: uppercase; white-space: nowrap;
  padding: 7px 11px; border-radius: 6px; margin-top: 2px;
  color: #fff;
}
.iuk-callout-ok  { background: #60a561; box-shadow: 0 4px 12px rgb(96 165 97 / 0.25); }
.iuk-callout-no  { background: #da4167; box-shadow: 0 4px 12px rgb(218 65 103 / 0.25); }
.iuk-callout-info{ background: rgb(var(--primary)); box-shadow: 0 4px 12px rgb(var(--primary) / 0.25); }
.iuk-callout-end { align-self: flex-end; }

/* Numbered annotation marker + caption list */
.iuk-marker {
  display: inline-grid; place-items: center;
  width: 18px; height: 18px; border-radius: 50%;
  background: rgb(var(--primary)); color: #fff;
  font-size: 10px; font-weight: 700; line-height: 1;
  box-shadow: 0 0 0 2px #fff, 0 2px 6px rgb(var(--primary) / 0.35);
  flex-shrink: 0;
}
.iuk-annotations { display: flex; flex-direction: column; gap: 8px; margin: 12px 0 0; padding: 0; list-style: none; }
.iuk-annotations li { display: flex; align-items: flex-start; gap: 9px; font-size: 13px; line-height: 1.5; color: rgb(var(--gray-700)); }
.dark .iuk-annotations li { color: rgb(var(--gray-300)); }
.iuk-annotations .iuk-marker { margin-top: 2px; box-shadow: 0 0 0 2px transparent; }

/* Absolutely-placed marker overlaying a scene */
.iuk-pin { position: absolute; z-index: 6; }

/* Partner-page wrapper: hatched, dashed — deliberately "not iDenfy" */
.iuk-partner {
  position: relative;
  background: repeating-linear-gradient(45deg, rgb(var(--gray-100)) 0, rgb(var(--gray-100)) 7px, transparent 7px, transparent 14px);
  border: 1.5px dashed rgb(var(--gray-300));
  border-radius: 14px;
  padding: 38px 18px 24px;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
}
.iuk-partner-lbl {
  position: absolute; top: -11px; left: 14px;
  display: flex; align-items: center; gap: 6px;
  font-weight: 700; font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
  color: rgb(var(--gray-500));
  background: rgb(var(--background-light, 255 255 255));
  padding: 6px 10px; border-radius: 5px;
  border: 1.5px dashed rgb(var(--gray-300));
  white-space: nowrap;
}
.dark .iuk-partner { background: repeating-linear-gradient(45deg, rgb(255 255 255 / 0.05) 0, rgb(255 255 255 / 0.05) 7px, transparent 7px, transparent 14px); border-color: rgb(255 255 255 / 0.18); }
.dark .iuk-partner-lbl { background: #17171b; color: rgb(var(--gray-400)); border-color: rgb(255 255 255 / 0.18); }

/* Brand tag pinned to the top edge of an embedded frame */
.iuk-embed { position: relative; display: flex; flex-direction: column; align-items: center; }
.iuk-embed-tag {
  position: absolute; top: -10px; left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; z-index: 5;
  font-weight: 700; font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase;
  color: #fff; background: rgb(var(--primary));
  padding: 5px 10px; border-radius: 5px; white-space: nowrap;
  box-shadow: 0 2px 6px rgb(var(--primary) / 0.3);
}

/* ---- Browser frame ---- */
.iuk-browser {
  display: flex; flex-direction: column; overflow: hidden;
  width: 100%; max-width: 100%;
  background: #fff;
  border: 1.5px solid rgb(var(--gray-300));
  border-radius: 10px;
  box-shadow: 0 4px 16px rgb(25 24 29 / 0.10);
}
.iuk-browser-brand { border-color: rgb(var(--primary)); box-shadow: 0 4px 16px rgb(var(--primary) / 0.18); }
.iuk-winbar {
  display: flex; align-items: center; gap: 6px; flex-shrink: 0;
  height: 24px; padding: 0 10px;
  background: #f3f4f6; border-bottom: 1px solid #e6e9ef;
}
.iuk-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.iuk-dot-r { background: #ff6b7e; }
.iuk-dot-y { background: #ffcc4d; }
.iuk-dot-g { background: #7bcb7d; }
.iuk-winbar-url {
  margin-left: 6px; flex: 1; min-width: 0;
  height: 12px; border-radius: 6px; background: #e6e9ef;
  display: flex; align-items: center; padding: 0 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 7px; font-weight: 600; color: #6f7486;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}

/* ---- Phone frame ---- */
.iuk-phone {
  position: relative;
  width: 100%; max-width: 232px;
  background: #19181d;
  border-radius: 22px;
  padding: 8px 6px;
  box-shadow: 0 8px 28px rgb(25 24 29 / 0.20);
}
.iuk-phone-screen {
  position: relative; overflow: hidden;
  background: #f7f8fa;
  border-radius: 16px;
}
.iuk-phone-notch {
  position: absolute; top: 3px; left: 50%; transform: translateX(-50%);
  width: 46px; height: 4px; border-radius: 3px;
  background: rgb(255 255 255 / 0.22); z-index: 3;
}

/* ========================= PRODUCT SKIN ================================= */
/* Fixed light. Traced from ui.idenfy.com. Never gets a .dark override. */

.iuk-shell {
  display: flex; flex-direction: column; gap: 12px;
  width: 100%; max-width: 420px; margin: 0 auto;
  padding: 14px 12px;
  background: #f7f8fa;
  color: #6f7486;
  font-size: 10px; line-height: 1.4;
  text-align: center;
}
.iuk-shell-flush { padding: 0; background: transparent; max-width: none; }
/* Standalone screen sitting directly on a docs page: keeps the product's own
   #f7f8fa page background so the ink-coloured logo stays legible. */
.iuk-shell-framed { border-radius: 8px; padding: 10px 9px; gap: 9px; }

/* Logo bar: left slot | centred logo | language chip */
.iuk-topbar { display: flex; align-items: center; gap: 8px; min-height: 24px; }
.iuk-topbar-slot { flex: 1 1 0; display: flex; align-items: center; min-width: 0; }
.iuk-topbar-slot-end { justify-content: flex-end; }
.iuk-logo {
  display: inline-flex; align-items: center;
  font-weight: 800; font-size: 11px; letter-spacing: -0.04em; color: #19181d;
}
.iuk-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 7px;
  background: #fff; border: 1px solid #d8dee9; border-radius: 4px;
  font-size: 9px; font-weight: 600; color: #6f7486;
  white-space: nowrap;
}
.iuk-chip svg { width: 10px; height: 10px; }

/* The card: flat outline, no shadow — matches ivs-layout exactly */
.iuk-card {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  padding: 16px 14px 13px;
  background: #fff;
  border-radius: 8px;
  min-width: 0; max-width: 100%;
  outline: 1px solid #d8dee9; outline-offset: -1px;
  text-align: center;
}
.iuk-card-body { display: flex; flex-direction: column; gap: 10px; width: 100%; max-width: 300px; margin: 0 auto; align-items: stretch; min-width: 0; }
.iuk-card-fluid .iuk-card-body { max-width: none; }

.iuk-h1 { margin: 0; font-size: 15px; font-weight: 700; line-height: 1.35; color: #19181d; }
.iuk-sub { margin: 0; font-size: 10px; font-weight: 600; line-height: 1.5; color: #6f7486; }
.iuk-h3 { margin: 0; font-size: 11px; font-weight: 600; line-height: 1.4; color: #19181d; text-align: left; }
.iuk-p  { margin: 0; font-size: 9px; font-weight: 400; line-height: 1.5; color: #6f7486; }
.iuk-fine { margin: 0; font-size: 8px; font-weight: 400; line-height: 1.5; color: #6f7486; }
/* Mintlify's prose styles reach inside snippets — pin these in both themes */
.iuk .iuk-h1, .dark .iuk .iuk-h1,
.iuk .iuk-h3, .dark .iuk .iuk-h3 { color: #19181d; }
.iuk .iuk-sub, .dark .iuk .iuk-sub,
.iuk .iuk-p, .dark .iuk .iuk-p,
.iuk .iuk-fine, .dark .iuk .iuk-fine { color: #6f7486; }
.iuk .iuk-card strong, .dark .iuk .iuk-card strong { color: #19181d; font-weight: 700; }
.iuk .iuk-card a, .dark .iuk .iuk-card a { color: #734bfb; font-weight: 600; text-decoration: none; }

/* Footer strip under the card */
.iuk-footer { font-size: 9px; font-weight: 400; line-height: 1.5; color: #6f7486; padding: 3px 0; }
.iuk .iuk-footer, .dark .iuk .iuk-footer { color: #6f7486; }
.iuk-footer-link { color: #734bfb; font-weight: 600; }

/* Card footer: stacked actions, gap 8px */
.iuk-actions { display: flex; flex-direction: column; gap: 6px; width: 100%; max-width: 300px; margin: 0 auto; }

/* ---- Buttons ---- */
.iuk-btn {
  display: grid; place-items: center; width: 100%;
  min-height: 32px; padding: 5px 11px;
  border: 1px solid transparent; border-radius: 4px;
  font-size: 11px; font-weight: 600; line-height: 1.3;
  text-align: center; user-select: none;
}
.iuk-btn-filled   { background: #734bfb; border-color: #734bfb; color: #fff; }
.iuk-btn-outlined { background: transparent; border-color: #734bfb; color: #734bfb; }
.iuk-btn-hover    { background: #452d97; border-color: #452d97; color: #fff; }
.iuk-btn-disabled { background: #eaeaeb; border-color: #eaeaeb; color: #c0c0c3; }
.iuk-btn-link {
  display: inline; width: auto; min-height: 0; padding: 0; border: 0;
  background: none; color: #734bfb; font-size: 10px; font-weight: 600;
}
.iuk-btn-link-disabled { color: #c0c0c3; }
.iuk .iuk-btn-filled, .dark .iuk .iuk-btn-filled,
.iuk .iuk-btn-hover, .dark .iuk .iuk-btn-hover { color: #fff; }
.iuk .iuk-btn-outlined, .dark .iuk .iuk-btn-outlined { color: #734bfb; }
.iuk .iuk-btn-disabled, .dark .iuk .iuk-btn-disabled { color: #c0c0c3; }

/* ---- Text field with floating label ---- */
.iuk-field { position: relative; width: 100%; text-align: left; }
.iuk-field-box {
  display: flex; align-items: center; gap: 6px;
  width: 100%; min-height: 30px; padding: 6px 9px;
  background: #fff; border: 1px solid #d8dee9; border-radius: 4px;
  font-size: 10px; font-weight: 600; line-height: 1.4; color: #19181d;
}
.iuk-field-label {
  position: absolute; top: -5px; left: 7px;
  padding: 0 3px; background: #fff;
  font-size: 8px; font-weight: 500; line-height: 1.2; color: #6f7486;
  white-space: nowrap;
}
.iuk-field-ph { color: #c0c0c3; font-weight: 500; }
.iuk-field-focus  .iuk-field-box   { border-color: #734bfb; }
.iuk-field-focus  .iuk-field-label { color: #734bfb; }
.iuk-field-error  .iuk-field-box   { border-color: #e91b0c; }
.iuk-field-error  .iuk-field-label { color: #e91b0c; }
.iuk-field-disabled .iuk-field-box   { border-color: #eaeaeb; color: #c0c0c3; }
.iuk-field-disabled .iuk-field-label { color: #c0c0c3; }
.iuk-field-caret { width: 1px; height: 12px; background: #734bfb; }
.iuk-field-req { color: #e91b0c; }
.iuk-field-msg {
  display: flex; align-items: center; gap: 5px;
  margin-top: 5px; font-size: 8px; font-weight: 400; line-height: 1.3; color: #e91b0c;
}
.iuk-field-msg svg { width: 9px; height: 9px; flex-shrink: 0; }
.iuk .iuk-field-box, .dark .iuk .iuk-field-box { color: #19181d; }
.iuk .iuk-field-label, .dark .iuk .iuk-field-label { color: #6f7486; }
.iuk .iuk-field-focus .iuk-field-label, .dark .iuk .iuk-field-focus .iuk-field-label { color: #734bfb; }
.iuk .iuk-field-msg, .dark .iuk .iuk-field-msg { color: #e91b0c; }
.iuk-caret-down { width: 0; height: 0; border-left: 3px solid transparent; border-right: 3px solid transparent; border-top: 4px solid #19181d; flex-shrink: 0; margin-left: auto; }

/* ---- OTP ---- */
.iuk-otp { display: flex; justify-content: center; gap: 6px; width: 100%; }
.iuk-otp-cell {
  display: grid; place-items: center;
  width: 30px; height: 30px;
  background: #fff; border: 1px solid #d8dee9; border-radius: 4px;
  font-size: 13px; font-weight: 600; color: #19181d;
}
.iuk-otp-cell-active { border-color: #734bfb; }
.iuk-otp-cell-error { border-color: #e91b0c; background: #ffebee; color: #e91b0c; }
.iuk .iuk-otp-cell, .dark .iuk .iuk-otp-cell { color: #19181d; }
.iuk .iuk-otp-cell-error, .dark .iuk .iuk-otp-cell-error { color: #e91b0c; }

/* ---- Checkbox ---- */
.iuk-check { display: flex; align-items: flex-start; gap: 7px; text-align: left; }
.iuk-check-box {
  width: 12px; height: 12px; flex-shrink: 0; margin-top: 1px;
  border: 1px solid #6f7486; border-radius: 3px; background: transparent;
  display: grid; place-items: center;
}
.iuk-check-on { background: #734bfb; border-color: #734bfb; color: #fff; }
.iuk-check-on svg { width: 8px; height: 8px; }
.iuk-check-lbl { font-size: 9px; font-weight: 400; line-height: 1.4; color: #6f7486; }
.iuk .iuk-check-lbl, .dark .iuk .iuk-check-lbl { color: #6f7486; }

/* ---- Selectable document / method card ---- */
.iuk-doccard {
  display: flex; align-items: center; gap: 7px;
  padding: 9px 12px;
  border: 1px solid #d8dee9; border-radius: 4px; background: #fff;
  text-align: left;
  min-width: 0; word-break: break-word;
}
.iuk-doccard > span { min-width: 0; }
.iuk-doccard-title { display: block; font-size: 10px; font-weight: 600; line-height: 1.35; color: #19181d; }
.iuk-doccard-desc  { display: block; font-size: 8px; font-weight: 400; line-height: 1.4; color: #6f7486; margin-top: 1px; }
.iuk-doccard-hover { background: #f2f4f8; }
.iuk-doccard-active { background: #efebff; border-color: #734bfb; }
.iuk-doccard-active .iuk-doccard-title { color: #452d97; }
.iuk-doccard-icon { width: 14px; height: 14px; flex-shrink: 0; color: #734bfb; }
.iuk .iuk-doccard-title, .dark .iuk .iuk-doccard-title { color: #19181d; }
.iuk .iuk-doccard-active .iuk-doccard-title, .dark .iuk .iuk-doccard-active .iuk-doccard-title { color: #452d97; }
.iuk .iuk-doccard-desc, .dark .iuk .iuk-doccard-desc { color: #6f7486; }
.iuk-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; width: 100%; }
.iuk-grid2 > * { min-width: 0; }

/* ---- Separator with label ---- */
.iuk-sep { display: flex; align-items: center; gap: 9px; font-size: 9px; color: #6f7486; width: 100%; }
.iuk-sep::before, .iuk-sep::after { content: ""; flex: 1; height: 1px; background: #d8dee9; }
.iuk .iuk-sep, .dark .iuk .iuk-sep { color: #6f7486; }

/* ---- Alert ---- */
.iuk-alert {
  display: flex; align-items: flex-start; gap: 7px;
  padding: 9px 10px; border-radius: 4px; border: 1px solid;
  text-align: left; color: #19181d;
}
.iuk-alert-center { align-items: center; }
.iuk-alert svg { width: 11px; height: 11px; flex-shrink: 0; margin-top: 1px; }
.iuk-alert-center svg { margin-top: 0; }
.iuk-alert-title { font-size: 10px; font-weight: 600; line-height: 1.4; }
.iuk-alert-text  { font-size: 9px; font-weight: 400; line-height: 1.45; }
.iuk-alert-info    { background: #e9f2ff; border-color: #1e7afd; }
.iuk-alert-info svg    { color: #1e7afd; }
.iuk-alert-success { background: #e8f5e9; border-color: #00c853; }
.iuk-alert-success svg { color: #00c853; }
.iuk-alert-warning { background: #fff3e0; border-color: #ff9800; }
.iuk-alert-warning svg { color: #ff9800; }
.iuk-alert-danger  { background: #ffebee; border-color: #e91b0c; }
.iuk-alert-danger svg  { color: #e91b0c; }
.iuk-alert-primary { background: #efebff; border-color: #734bfb; }
.iuk-alert-primary svg { color: #734bfb; }
.iuk .iuk-alert, .dark .iuk .iuk-alert { color: #19181d; }

/* ---- Tip: icon + text, no box ---- */
.iuk-tip { display: flex; align-items: flex-start; gap: 7px; text-align: left; }
.iuk-tip svg { width: 11px; height: 11px; flex-shrink: 0; margin-top: 1px; color: #734bfb; }
.iuk-tip-error svg { color: #e91b0c; }
.iuk-tip-text { font-size: 9px; font-weight: 400; line-height: 1.5; color: #6f7486; }
.iuk .iuk-tip-text, .dark .iuk .iuk-tip-text { color: #6f7486; }

/* ---- Info field: purple confirmation pill ---- */
.iuk-infofield {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 11px;
  background: #efebff; border: 1px solid #d8dee9; border-radius: 4px;
  text-align: left;
}
.iuk-infofield svg { width: 11px; height: 11px; flex-shrink: 0; color: #734bfb; }
.iuk-infofield-text { font-size: 9px; font-weight: 400; line-height: 1.45; color: #19181d; }
.iuk .iuk-infofield-text, .dark .iuk .iuk-infofield-text { color: #19181d; }

/* ---- Timer ---- */
.iuk-timer {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 10px; font-weight: 600; color: #6f7486;
}
.iuk-timer svg { width: 11px; height: 11px; }
.iuk-timer-val { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: 0.02em; }
.iuk .iuk-timer, .dark .iuk .iuk-timer { color: #6f7486; }

/* ---- Spinner (static arc — no animation, docs visuals are still) ---- */
.iuk-spinner { display: grid; place-items: center; padding: 14px 0; }
.iuk-spinner svg { width: 44px; height: 44px; color: #734bfb; }

/* ---- Result icon ---- */
.iuk-result { display: grid; place-items: center; gap: 9px; padding: 6px 0; }
.iuk-result svg { width: 56px; height: 56px; }
.iuk-result-success svg { color: #00c853; }
.iuk-result-warning svg { color: #ff9800; }
.iuk-result-danger  svg { color: #e91b0c; }

/* ---- Camera frame ---- */
.iuk-cam {
  position: relative; overflow: hidden; width: 100%;
  background: #19181d;
  border: 1px solid #d8dee9; border-radius: 8px;
}
.iuk-cam-43   { aspect-ratio: 4 / 3; }
.iuk-cam-169  { aspect-ratio: 16 / 9; }

/* document overlay: bright window punched out of a dark surround */
.iuk-cam-window {
  position: absolute; top: 7.5%; left: 10%; right: 10%; bottom: 7.5%;
  border-radius: 4px;
  box-shadow: 0 0 8px 140px rgb(0 0 0 / 0.35);
}
.iuk-cam-corners { position: absolute; inset: 0; border: 3px solid rgb(255 255 255 / 0.15); border-radius: 4px; }
.iuk-cam-corner { position: absolute; width: 9%; height: 14%; }
.iuk-cam-corner-tl { top: 0; left: 0;  border-top: 3px solid #fff; border-left: 3px solid #fff;  border-top-left-radius: 4px; }
.iuk-cam-corner-tr { top: 0; right: 0; border-top: 3px solid #fff; border-right: 3px solid #fff; border-top-right-radius: 4px; }
.iuk-cam-corner-bl { bottom: 0; left: 0;  border-bottom: 3px solid #fff; border-left: 3px solid #fff;  border-bottom-left-radius: 4px; }
.iuk-cam-corner-br { bottom: 0; right: 0; border-bottom: 3px solid #fff; border-right: 3px solid #fff; border-bottom-right-radius: 4px; }

/* face oval: masked surround + a ring that changes colour by state */
.iuk-cam-oval {
  position: absolute; inset: 0;
  background: radial-gradient(ellipse 34% 44% at 50% 46%, rgb(0 0 0 / 0) 50%, rgb(38 37 45 / 0.30) 50%);
}
.iuk-cam-ring {
  position: absolute; top: 2%; left: 16%; width: 68%; height: 88%;
  border: 3px solid #fff; border-radius: 50%;
}
.iuk-cam-ok    .iuk-cam-ring { border-color: #00c853; }
.iuk-cam-error .iuk-cam-ring { border-color: #e91b0c; }

/* camera hint pill */
.iuk-cam-hint {
  position: absolute; left: 50%; bottom: 7%; transform: translateX(-50%);
  padding: 4px 9px; border-radius: 50rem;
  background: rgb(25 24 29 / 0.62);
  font-size: 8px; font-weight: 600; color: #fff; white-space: nowrap;
}
.iuk .iuk-cam-hint, .dark .iuk .iuk-cam-hint { color: #fff; }

/* upload empty state */
.iuk-cam-upload {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  background: #f7f8fa; color: #6f7486; text-align: center; padding: 10px;
}
.iuk-cam-upload svg { width: 16px; height: 16px; color: #734bfb; }
.iuk-cam-upload-lbl { font-size: 9px; font-weight: 600; color: #734bfb; }
.iuk .iuk-cam-upload-lbl, .dark .iuk .iuk-cam-upload-lbl { color: #734bfb; }

/* review scrim over a captured shot */
.iuk-cam-scrim {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  background: rgb(44 45 55 / 0.70); color: #fff; text-align: center; padding: 10px;
  font-size: 8px; line-height: 1.4;
}
.iuk .iuk-cam-scrim, .dark .iuk .iuk-cam-scrim { color: #fff; }

/* shutter */
.iuk-cam-shutter {
  position: absolute; left: 50%; bottom: 6%; transform: translateX(-50%);
  width: 22px; height: 22px; border-radius: 50%;
  border: 2px solid #fff; display: grid; place-items: center;
}
.iuk-cam-shutter::after { content: ""; width: 14px; height: 14px; border-radius: 50%; background: #734bfb; }

/* ---- Stylised ID document artwork ---- */
.iuk-idcard {
  position: relative; overflow: hidden;
  width: 82%; aspect-ratio: 1.585;
  border-radius: 4px;
  background: linear-gradient(135deg, #a98bff 0%, #d8b4fe 50%, #fecdd3 100%);
}
.iuk-idcard-photo { position: absolute; left: 8%; top: 14%; width: 26%; height: 56%; border-radius: 2px; background: rgb(255 255 255 / 0.45); }
.iuk-idcard-lines { position: absolute; left: 40%; right: 9%; top: 18%; height: 46%; background: repeating-linear-gradient(180deg, transparent 0, transparent 4px, rgb(255 255 255 / 0.5) 4px, rgb(255 255 255 / 0.5) 6px); }
.iuk-idcard-mrz  { position: absolute; left: 8%; right: 8%; bottom: 9%; height: 13%; background: repeating-linear-gradient(90deg, rgb(255 255 255 / 0.55) 0, rgb(255 255 255 / 0.55) 3px, transparent 3px, transparent 6px); }
.iuk-cam-center { position: absolute; inset: 0; display: grid; place-items: center; }

/* ---- Flow strip ---- */
.iuk-strip { display: flex; gap: 12px; align-items: flex-start; flex-wrap: wrap; }
.iuk-strip-item { flex: 0 1 168px; min-width: 0; display: flex; flex-direction: column; gap: 7px; }
.iuk-strip-cap { font-size: 11px; font-weight: 600; line-height: 1.35; color: rgb(var(--gray-700)); text-align: center; }
.dark .iuk-strip-cap { color: rgb(var(--gray-300)); }

/* ---- Bank card artwork (payment card, distinct from IdCard) ---- */
.iuk-bankcard {
  position: relative; overflow: hidden;
  width: 84%; aspect-ratio: 1.585;
  border-radius: 5px;
  background: linear-gradient(135deg, #5b41c8 0%, #7c58f0 46%, #a98bff 100%);
  box-shadow: 0 3px 10px rgb(25 24 29 / 0.28);
}
.iuk-bankcard-chip {
  position: absolute; left: 9%; top: 27%; width: 15%; height: 20%;
  border-radius: 2px;
  background: linear-gradient(160deg, #ffd88a, #e0a82e);
}
.iuk-bankcard-chip::after {
  content: ""; position: absolute; inset: 26% 12%;
  background: repeating-linear-gradient(90deg, rgb(0 0 0 / 0.18) 0, rgb(0 0 0 / 0.18) 1px, transparent 1px, transparent 3px);
}
.iuk-bankcard-num {
  position: absolute; left: 9%; right: 9%; top: 56%;
  display: flex; justify-content: space-between; gap: 4%;
}
.iuk-bankcard-num span {
  flex: 1; height: 5px; border-radius: 2px;
  background: rgb(255 255 255 / 0.62);
}
.iuk-bankcard-num span:last-child { background: rgb(255 255 255 / 0.92); }
.iuk-bankcard-name {
  position: absolute; left: 9%; width: 44%; bottom: 13%;
  height: 4px; border-radius: 2px; background: rgb(255 255 255 / 0.5);
}
.iuk-bankcard-brand {
  position: absolute; right: 9%; bottom: 11%;
  width: 16%; height: 9%; border-radius: 2px;
  background: rgb(255 255 255 / 0.42);
}

/* card-shaped capture window: wider and shallower than the document one */
.iuk-cam-window-card {
  position: absolute; top: 20%; left: 11%; right: 11%; bottom: 20%;
  border-radius: 5px;
  box-shadow: 0 0 8px 140px rgb(0 0 0 / 0.35);
}
.iuk-cam-corners-card { position: absolute; top: 20%; left: 11%; right: 11%; bottom: 20%; border-radius: 5px; }
.iuk-cam-corners-card .iuk-cam-corner { width: 13%; height: 22%; }

/* ---- Upload dropzone (traced from bank-card.idenfy.com .file-select-box) ---- */
.iuk-upload {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; width: 100%; min-height: 74px; padding: 12px 10px;
  text-align: center; color: #19181d;
  background: #f2f4f8; border-radius: 4px;
  outline: 1px dashed #d8dee9; outline-offset: -1px;
}
.iuk-upload-drag { background: #d8dee9; }
.iuk-upload svg { width: 16px; height: 16px; color: #734bfb; flex-shrink: 0; }
.iuk-upload-prompt { font-size: 9px; font-weight: 400; line-height: 1.45; color: #19181d; }
.iuk-upload-trigger { color: #734bfb; font-weight: 600; }
.iuk-upload-hint { font-size: 8px; font-weight: 400; line-height: 1.4; color: #6f7486; }
.iuk .iuk-upload-prompt, .dark .iuk .iuk-upload-prompt { color: #19181d; }
.iuk .iuk-upload-trigger, .dark .iuk .iuk-upload-trigger { color: #734bfb; }
.iuk .iuk-upload-hint, .dark .iuk .iuk-upload-hint { color: #6f7486; }

/* ---- Uploaded-file row (PDFs get no preview) ---- */
.iuk-filerow {
  display: flex; align-items: center; gap: 8px;
  width: 100%; min-height: 74px; padding: 12px;
  background: #f7f8fa; border: 1px solid #d8dee9; border-radius: 8px;
}
.iuk-filerow svg { width: 14px; height: 14px; flex-shrink: 0; color: #6f7486; }
.iuk-filerow-name { display: block; font-size: 9px; font-weight: 600; line-height: 1.4; color: #19181d; word-break: break-all; min-width: 0; }
.iuk-filerow-meta { display: block; font-size: 8px; font-weight: 400; line-height: 1.4; color: #6f7486; margin-top: 2px; }
.iuk .iuk-filerow-name, .dark .iuk .iuk-filerow-name { color: #19181d; }
.iuk .iuk-filerow-meta, .dark .iuk .iuk-filerow-meta { color: #6f7486; }

/* ---- Desktop hand-off ---- */
.iuk-handoff { display: flex; flex-direction: column; align-items: center; gap: 9px; width: 100%; }
.iuk-qr {
  width: 76px; height: 76px; padding: 5px; flex-shrink: 0;
  background: #fff; border: 1px solid #d8dee9; border-radius: 4px;
}
.iuk-qr svg { display: block; width: 100%; height: 100%; color: #19181d; }
.iuk-handoff-or { font-size: 8px; font-weight: 600; color: #6f7486; text-transform: uppercase; letter-spacing: 0.06em; }
.iuk .iuk-handoff-or, .dark .iuk .iuk-handoff-or { color: #6f7486; }
.iuk-handoff-escape { font-size: 8px; font-weight: 600; line-height: 1.4; color: #734bfb; text-align: center; }
.iuk .iuk-handoff-escape, .dark .iuk .iuk-handoff-escape { color: #734bfb; }

/* ---- Masked card option ---- */
.iuk-maskedcard {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 9px 11px; min-width: 0;
  background: #fff; border: 1px solid #d8dee9; border-radius: 4px;
}
.iuk-maskedcard-active { background: #efebff; border-color: #734bfb; }
.iuk-maskedcard-num {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10px; font-weight: 600; color: #19181d; letter-spacing: 0.04em;
}
.iuk-maskedcard-active .iuk-maskedcard-num { color: #452d97; }
.iuk-maskedcard-exp { font-size: 8px; font-weight: 500; color: #6f7486; white-space: nowrap; }
.iuk .iuk-maskedcard-num, .dark .iuk .iuk-maskedcard-num { color: #19181d; }
.iuk .iuk-maskedcard-active .iuk-maskedcard-num, .dark .iuk .iuk-maskedcard-active .iuk-maskedcard-num { color: #452d97; }
.iuk .iuk-maskedcard-exp, .dark .iuk .iuk-maskedcard-exp { color: #6f7486; }

/* ---- Consent assurance panel ---- */
.iuk-assurances {
  display: flex; flex-direction: column; gap: 7px;
  width: 100%; padding: 11px 12px;
  background: #f2f4f8; border-radius: 4px;
}
.iuk-assurance { display: flex; align-items: center; gap: 8px; text-align: left; }
.iuk-assurance-chip {
  display: grid; place-items: center; flex-shrink: 0;
  width: 19px; height: 19px; border-radius: 4px; background: #fff;
}
.iuk-assurance-chip svg { width: 11px; height: 11px; color: #734bfb; }
.iuk-assurance-text { font-size: 9px; font-weight: 400; line-height: 1.4; color: #19181d; min-width: 0; }
.iuk .iuk-assurance-text, .dark .iuk .iuk-assurance-text { color: #19181d; }

/* ---- Modal / dialog (traced from .custom-dialog + ivs-message-frame) ---- */
.iuk-modalwrap {
  position: relative; overflow: hidden;
  padding: 16px 12px;
  background: #3a3743; border-radius: 8px;
}
.iuk-modal {
  display: flex; flex-direction: column; overflow: hidden;
  width: 100%; max-width: 300px; margin: 0 auto;
  background: #fff; border-radius: 4px;
  box-shadow: 0 8px 24px rgb(0 0 0 / 0.08), 0 2px 2px rgb(0 0 0 / 0.02);
}
.iuk-modal-head {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 12px; border-bottom: 1px solid #d8dee9;
}
.iuk-modal-title { font-size: 11px; font-weight: 700; line-height: 1.35; color: #19181d; min-width: 0; }
.iuk-modal-body { padding: 12px; text-align: center; }
.iuk-modal-panel {
  padding: 12px 10px; border-radius: 2px;
  background: #f7f8fa; border: 1px solid #d8dee9;
}
.iuk-modal-art { display: grid; place-items: center; margin-bottom: 9px; }
.iuk-modal-art svg { width: 40px; height: 40px; color: #ff9800; }
.iuk-modal-msg { font-size: 9px; font-weight: 600; line-height: 1.45; color: #19181d; }
.iuk-modal-foot { padding: 10px 12px 12px; border-top: 1px solid #d8dee9; }
.iuk .iuk-modal-title, .dark .iuk .iuk-modal-title,
.iuk .iuk-modal-msg, .dark .iuk .iuk-modal-msg { color: #19181d; }

/* ---- Shutter row: switch | shutter | upload ---- */
.iuk-shutterbar { display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%; padding: 4px 0; }
.iuk-shutterbar-side { flex: 1 1 0; display: grid; place-items: center; }
.iuk-shutterbar-side svg { width: 15px; height: 15px; color: #6f7486; }
.iuk-shutter-btn { width: 26px; height: 26px; border-radius: 50%; border: 2px solid #734bfb; display: grid; place-items: center; flex-shrink: 0; }
.iuk-shutter-btn::after { content: ""; width: 17px; height: 17px; border-radius: 50%; background: #734bfb; }
.iuk-shutter-off { border-color: #eaeaeb; }
.iuk-shutter-off::after { background: #eaeaeb; }
`;
  return <style>{css}</style>;
};

<UiKitStyles />

<Info>
  This page covers the **standalone** flow — the card check running on its own token, with no identity verification behind it. For the version that runs as an extra step inside a KYC session, see [Bank Card Verification](/guides/dashboard/features/bank-card-verification).
</Info>

Bank Card Verification confirms that a payment card belongs to the person presenting it. The end user photographs the card, or uploads a card-confirmation document. The cardholder name and card number read from it are compared against the name — and optionally the last four digits — supplied by the company that requested the check.

Card capture and card image processing run in a dedicated environment certified to **PCI-DSS v4.0.1**, and no card imagery is retained once processing completes.

***

## Where to Find It

The same card step serves two entry points.

* **Inside a KYC session** — a step shown after identity document capture, only when the feature is enabled for that partner. The KYC verification **cannot be submitted** until the card step has resolved.
* **As a standalone link** — bank card verification only, no identity verification required.

Both settings that govern the feature live under [Settings → Know Your Customer → Configuration](/guides/dashboard/settings/configuration): **Bank Card Verification** turns it on, and **Bank Card PDF Upload** controls whether the upload option appears at all. Neither is self-service — [contact iDenfy](https://idenfy-ivs.atlassian.net/servicedesk/customer/portal/1) to request access.

***

## The Standalone Flow

<Steps>
  <Step title="Consent">
    <Columns cols={2}>
      <div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
        Four assurances, and a single **Agree & continue securely** button — there is no checkbox to tick. The screen is skipped entirely if consent was already given for this session.
      </div>

      <div>
        <SceneRow>
          <Scene label="Consent screen" dim="standalone only">
            <IdvShell footer={false} lang="EN">
              <IdvCard title="Verify your bank card" sub="Your identity is already verified. Confirm your card belongs to you." footer={<Btn>Agree &amp; continue securely</Btn>}>
                <Assurances
                  items={[
            "CVV is never stored",
            "Full card number is not stored",
            "Used only to confirm card ownership",
            "Certified to ISO 27001, SOC 2, and PCI DSS. Compliant with GDPR and CCPA."
          ]}
                />
              </IdvCard>
            </IdvShell>
          </Scene>
        </SceneRow>
      </div>
    </Columns>
  </Step>

  <Step title="Desktop Hand-Off">
    <Columns cols={2}>
      <div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
        Desktop users see a device screen first, offering a QR code and an SMS link. **Continue in app** appears only when the session carries a mobile code. The footer escape — *Don't have a smartphone? Continue on current device.* — lets them stay put.

        Once the phone finishes, the desktop advances to the result on its own; it polls in the background, so the user doesn't need to do anything on the original screen.
      </div>

      <div>
        <SceneRow>
          <Scene label="Device screen" dim="desktop only">
            <IdvShell footer={false} lang="EN">
              <IdvCard title="Verify your bank card" sub="Continue on your phone to use its camera." footer={<Btn state="disabled">Continue</Btn>}>
                <DeviceHandoff escape="Don't have a smartphone? Continue on current device." />
              </IdvCard>
            </IdvShell>
          </Scene>
        </SceneRow>
      </div>
    </Columns>
  </Step>

  <Step title="Starting Options">
    <Columns cols={2}>
      <div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
        | Option                  | Availability                                                                                          |
        | ----------------------- | ----------------------------------------------------------------------------------------------------- |
        | **Capture with camera** | Always available                                                                                      |
        | **Upload a PDF**        | Only when PDF upload is enabled for that partner. Otherwise the tile is hidden entirely, not disabled |

        If only one method exists it is preselected. **Continue** stays disabled until a method is picked.
      </div>

      <div>
        <SceneRow>
          <Scene label="Method selection" dim="both entry points">
            <IdvShell footer={false} lang="EN">
              <IdvCard title="Verify your bank card" sub="Choose how to confirm your card ownership." footer={<><Timer value="29:45" /><Btn state="disabled">Continue</Btn></>}>
                <DocCard title="Capture with camera" desc="Use your camera to capture the card" icon="camera" state="active" />

                <DocCard title="Upload a PDF" desc="Only shown when PDF upload is enabled" icon="document" />

                <Text size="fine">🔒 Only your card number and name are read – CVV is never captured or stored.</Text>
              </IdvCard>
            </IdvShell>
          </Scene>
        </SceneRow>
      </div>
    </Columns>
  </Step>

  <Step title="Camera Path">
    <Columns cols={2}>
      <div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
        **Capture your card** shows a live view with a card frame. There is **no auto-capture** — the shutter is manual. A camera-switch button appears only if a second camera exists.

        **Inspect captured card** asks the three questions shown, then offers confirm or retake. There is no back button on this screen.

        If details are missing, **Flip your card** appears and the other side is requested. The back side is **always camera-captured**, even when the front was uploaded.
      </div>

      <div>
        <SceneRow>
          <Scene label="Capture" dim="manual shutter">
            <IdvShell footer={false} lang="">
              <IdvCard title="Capture your card">
                <CameraFrame ratio="16/9" overlay="card" />

                <ShutterBar />
              </IdvCard>
            </IdvShell>
          </Scene>

          <Scene label="Inspect" dim="no back button">
            <IdvShell footer={false} lang="">
              <IdvCard title="Inspect captured card" footer={<><Btn>Confirm</Btn><Btn variant="outlined">Retake</Btn></>}>
                <CameraFrame ratio="16/9" overlay="card" />

                <InfoField>Is the card fully in frame?</InfoField>
                <InfoField>Is anything covering the card?</InfoField>
                <InfoField>Is all the text legible?</InfoField>
              </IdvCard>
            </IdvShell>
          </Scene>
        </SceneRow>
      </div>
    </Columns>
  </Step>

  <Step title="Upload Path">
    <Columns cols={2}>
      <div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
        Accepted formats are **PNG, JPG, HEIF and PDF**, one file at a time.

        <Warning>
          **The size hint and the real limit differ.** The control shows a 5 MB hint, but that isn't enforced in the browser — the server accepts up to **10 MB**. Files between the two still go through. Anything larger comes back rejected with a message.
        </Warning>

        PDFs get no image preview; the file name is shown instead. **Review uploaded document** then asks whether it shows the card number, whether the name is visible, and whether it's the right document, before continue or upload again.
      </div>

      <div>
        <SceneRow>
          <Scene label="Upload" dim="one file at a time">
            <IdvShell footer={false} lang="">
              <IdvCard title="Upload your card confirmation" footer={<Btn state="disabled">Continue</Btn>}>
                <UploadBox prompt="Drag a file here or" trigger="browse" hint="PNG, JPG, HEIF or PDF · up to 5 MB" />
              </IdvCard>
            </IdvShell>
          </Scene>

          <Scene label="PDF selected" dim="no image preview">
            <IdvShell footer={false} lang="">
              <IdvCard title="Review uploaded document" footer={<><Btn>Continue</Btn><Btn variant="outlined">Upload again</Btn></>}>
                <FilePreview name="card-confirmation-statement.pdf" meta="PDF · 1.2 MB" />

                <InfoField>Does it show the card number?</InfoField>
                <InfoField>Is the name visible?</InfoField>
                <InfoField>Is it the right document?</InfoField>
              </IdvCard>
            </IdvShell>
          </Scene>
        </SceneRow>
      </div>
    </Columns>
  </Step>

  <Step title="Multiple Cards">
    <Columns cols={2}>
      <div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
        If several cards are found in the document, **Which card are you verifying?** offers masked options — last four digits and expiry only — as many as were detected.
      </div>

      <div>
        <SceneRow>
          <Scene label="Multiple cards detected">
            <IdvShell footer={false} lang="">
              <IdvCard title="Which card are you verifying?" footer={<Btn>Continue</Btn>}>
                <MaskedCard last4="1532" expiry="09/28" state="active" />

                <MaskedCard last4="8841" expiry="04/27" />
              </IdvCard>
            </IdvShell>
          </Scene>
        </SceneRow>
      </div>
    </Columns>
  </Step>
</Steps>

***

## Quality Problems

<Columns cols={2}>
  <div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
    Quality checks run **after submitting**, not live during capture. A problem opens a modal with an illustration, a single message, and one **Try again** button that re-prompts the same side.

    | Message group | Covers                                                                                  |
    | ------------- | --------------------------------------------------------------------------------------- |
    | Image quality | Blurry · glare · bad lighting                                                           |
    | Framing       | Card not detected · move closer · card cut off · center your card                       |
    | Content       | Multiple cards found                                                                    |
    | Authenticity  | Physical card required (a photo of a screen) · authentic card required (a printed copy) |

    <Note>
      Quality problems **spend no attempt** on their own. But three consecutive quality failures within one attempt do consume that attempt.
    </Note>
  </div>

  <div>
    <SceneRow>
      <Scene label="Quality modal" dim="spends no attempt">
        <Modal title="Check your photo" message="The photo is too blurry to read." tone="warning" footer={<Btn>Try again</Btn>} />
      </Scene>
    </SceneRow>
  </div>
</Columns>

***

## Attempts and Timers

Three attempts by default, configurable per partner. **The counter is never shown to the user.**

| Outcome                                      | Spends an attempt?                                      |
| -------------------------------------------- | ------------------------------------------------------- |
| `This document doesn't contain card details` | **Yes** — restarts from the front side                  |
| `We couldn't confirm your card is genuine`   | **Yes** — restarts from the front side                  |
| Starting a fresh front capture mid-flow      | **Yes**                                                 |
| A quality problem                            | No — unless three land consecutively within one attempt |
| `Verification temporarily unavailable`       | No — retryable                                          |

### Two Independent Clocks

| Clock             | Default | Range         | Starts                                           |
| ----------------- | ------- | ------------- | ------------------------------------------------ |
| Link lifetime     | 1 hour  | up to 30 days | when the link is issued                          |
| Session countdown | —       | 1–60 minutes  | **at the capture step**, not when the link opens |

A **Time left** indicator appears only if enabled for the partner, and is hidden during mobile capture.

### Timeouts

Analysis waits up to **60 seconds**; camera and loading up to **15**. Failures show *Verification temporarily unavailable*, which is retryable and spends no attempt. Camera failures return the user to the method screen, so upload stays reachable.

***

## Limits and Behaviour

<Warning>
  **Embedding in your own page?** Your frame must grant camera access to the card capture origin, or card capture fails while document capture keeps working. This asymmetry is a frequent support cause — see [Redirect & iFrame](/kyc/iframe-redirect#required-attributes) for the `allow` attribute.
</Warning>

**SMS limits.** One per session, one per phone number per 24 hours, and three requests per 15 minutes. Users in unsupported phone countries are told to scan the QR code instead.

**Languages.** All [37 supported languages](/resources/supported-languages), switchable mid-flow, including right-to-left rendering for Arabic and Persian (Farsi).

**What these screens don't have.** No **Cancel verification** button and no **Continue on mobile** button. There is no card-brand or country restriction, and **no manual review** — the result is final.

***

## Results

### Standalone

One screen, no buttons. Only a **full match** counts as success. If redirect URLs were configured, success and failure hop straight back to your page — the expired case **never** redirects.

<SceneRow>
  <Scene label="Success" dim="full match only" tone="ok">
    <IdvShell footer={false} lang="">
      <IdvCard title="Card verified successfully">
        <ResultIcon tone="success" />
      </IdvCard>
    </IdvShell>
  </Scene>

  <Scene label="Unsuccessful" tone="no">
    <IdvShell footer={false} lang="">
      <IdvCard title="Card verification unsuccessful" sub="Contact the service that requested this verification.">
        <ResultIcon tone="danger" />
      </IdvCard>
    </IdvShell>
  </Scene>

  <Scene label="Expired link">
    <IdvShell footer={false} lang="">
      <IdvCard title="This verification link is no longer valid">
        <ResultIcon tone="warning" />
      </IdvCard>
    </IdvShell>
  </Scene>
</SceneRow>

### Inside a KYC Session

There is no result screen at all. The flow simply continues to the next step, and a mismatch is flagged to you rather than shown to the user. Results appear alongside the identity verification in [Verification Details](/guides/dashboard/kyc/verification-details).

***

<CardGroup cols={2}>
  <Card title="Bank Card Verification" icon="credit-card" href="/guides/dashboard/features/bank-card-verification">
    The card check as an additional step inside the identity verification flow, and how the verdict is decided.
  </Card>

  <Card title="Configuration" icon="gear" href="/guides/dashboard/settings/configuration">
    The Bank Card Verification and Bank Card PDF Upload settings that govern both flows.
  </Card>
</CardGroup>


## Related topics

- [Bank Card Verification](/guides/dashboard/features/bank-card-verification.md)
- [Configuration](/guides/dashboard/settings/configuration.md)
- [Verification Details](/guides/dashboard/kyc/verification-details.md)
- [iOS SDK Additional Features](/sdks/ios/additional-features.md)
- [Android SDK Additional Features](/sdks/android/additional-features.md)
