/* KYC Integration — sign-in ("Organic").
 *
 * The desk's warm claymorphic look, carried onto the pages a reviewer sees
 * before the desk exists: /login and its sibling states (forgot password, email
 * link, verify email). Frappe renders these from frappe/www/login.html, so this
 * file styles the framework's own markup rather than replacing the template —
 * an upgrade that changes the form keeps working, it just looks plain again.
 *
 * On a wide screen it is a split: a fixed clay panel on the left carrying the
 * mark, the wordmark and a strapline, with the form on the warm ground beside
 * it. The panel is drawn out of pseudo-elements — body::before is its surface
 * and mark, body::after the wordmark, and the visible section::before the
 * strapline (login.js keeps exactly one section on screen at a time, so that
 * last one renders exactly once). It is built this way for the same reason the
 * rest of the file is: no template is replaced, so an upgrade that changes the
 * form cannot break sign-in. Below 900px the panel is dropped and the card
 * stands alone, centred.
 *
 * SCOPING IS LOAD-BEARING. web_include_css has no per-route granularity, so
 * this file is served on every website page, including the tenant-facing
 * /verify flow — which must keep its own admin-configured branding. Every rule
 * below is therefore scoped to the two routes that render this card:
 *
 *     body:is([data-path="login"], [data-path="update-password"])
 *
 * (base.html stamps the route onto the body). /update-password is the same
 * markup — login-content page-card, page-card-head, password-field, the lot —
 * so it is the same page to every rule here; left out of the scope, it was the
 * one screen in the sign-in flow arriving in the framework's plain grey. :is()
 * takes the specificity of its most specific argument, so this reads exactly as
 * [data-path="login"] did in every cascade calculation below. Do not add an
 * unscoped rule to this file.
 *
 * The @font-face blocks are the one exception, and are deliberately duplicated
 * from fonts/fonts.css rather than pulling that file in site-wide: a font
 * declaration is inert until something asks for the family, so declaring these
 * two costs /verify nothing, whereas fonts.css also declares Inter — which
 * /verify already loads from its branding font URL, and two sources for one
 * family is a rendering difference we are not entitled to make there.
 */

@font-face {
	font-family: "Figtree";
	font-style: normal;
	font-weight: 300 900;
	font-display: swap;
	src: url("/assets/kyc_integration/fonts/Figtree-latin-ext.woff2") format("woff2");
	unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308,
		U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
		U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
	font-family: "Figtree";
	font-style: normal;
	font-weight: 300 900;
	font-display: swap;
	src: url("/assets/kyc_integration/fonts/Figtree-latin.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
		U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
	font-family: "Caprasimo";
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url("/assets/kyc_integration/fonts/Caprasimo-latin-ext.woff2") format("woff2");
	unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308,
		U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
		U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
	font-family: "Caprasimo";
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url("/assets/kyc_integration/fonts/Caprasimo-latin.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
		U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

body:is([data-path="login"], [data-path="update-password"]) {
	--kyc-brand: #c67139;
	--kyc-brand-600: #b2622d;
	--kyc-brand-700: #8c491a;
	--kyc-bg: #f5ead8;
	--kyc-surface: #faf5ec;
	--kyc-ink: #201e1d;
	--kyc-ink-3: #645c50;
	/* ink-4 is 3.95:1 on the card and 3.61:1 on the ground: it is for icons and
	 * for a disabled control's label, both of which owe less than body text does.
	 * Anything a reader has to read takes ink-3 (6.06:1 / 5.53:1). */
	--kyc-ink-4: #82796a;
	--kyc-line: #e6dac2;
	/* The framework caps .page-card at max-width: 371px, which no `width` can
	 * out-argue — so the card was 371px while the note injected under it took the
	 * 420 it asked for and stood proud on both sides. Both read this. */
	--kyc-card-w: 420px;

	background: radial-gradient(1100px 620px at 50% -12%, #f9f4ed, var(--kyc-bg) 62%) no-repeat;
	background-color: var(--kyc-bg);
	color: var(--kyc-ink);
	font-family: "Figtree", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
	min-height: 100vh;
	/* svh, so a phone's address bar cannot make the page taller than the screen
	 * and put a scrollbar under a form that fits. The vh line above is the
	 * fallback for engines that do not know the unit. */
	min-height: 100svh;
}

/* ------------------------------------------------------------- brand ------ */

/* The framework's <img class="app-logo"> is whatever Website Settings points at
 * — on a stock site, Frappe's own grey cube. Swap in the service's mark so the
 * first screen of the product is already the product. */
body:is([data-path="login"], [data-path="update-password"]) .page-card-head .app-logo {
	display: none;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card-head::before {
	content: "";
	display: block;
	width: 84px;
	height: 84px;
	margin: 0 auto 16px;
	background: url("/assets/kyc_integration/images/kyc-mark.svg") center / contain no-repeat;
	filter: drop-shadow(0 14px 24px rgba(140, 73, 26, 0.28));
}

body:is([data-path="login"], [data-path="update-password"]) .page-card-head h4 {
	font-family: "Caprasimo", "Figtree", system-ui, sans-serif;
	font-weight: 400;
	font-size: 27px;
	line-height: 1.15;
	letter-spacing: -0.015em;
	color: var(--kyc-ink);
	margin: 0;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card-head::after {
	content: "Identity Verification";
	display: block;
	margin-top: 5px;
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--kyc-ink-3);
}

/* The line under the heading, and the labels over the fields: the framework's
 * cool greys read as a different product's greys on a warm card. */
body:is([data-path="login"], [data-path="update-password"]) .page-card-head .page-card-subtitle {
	font-size: 14.5px;
	color: var(--kyc-ink-3);
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .form-label {
	font-size: 12.5px;
	font-weight: 600;
	letter-spacing: 0.01em;
	color: var(--kyc-ink-3);
}

/* --------------------------------------------------------------- card ----- */

/* The framework parks the card 60px from the top of a viewport it sized at
 * 100vh - 220px, which on a desk monitor leaves the form stranded above a field
 * of empty ground. Centre it instead, in both directions. */
/* The website bundle floors .page_content at 50vh. Inside a column that is
 * already centring against 100vh, that floor is dead weight at the bottom of it:
 * the card rides high and the note injected under it drifts away from the card
 * it belongs to. */
body:is([data-path="login"], [data-path="update-password"]) .page_content {
	min-height: 0;
}

body:is([data-path="login"], [data-path="update-password"]) .page-content-wrapper {
	box-sizing: border-box;
	display: flex;
	flex-direction: column;
	justify-content: center;
	min-height: 100vh;
	min-height: 100svh;
	padding-top: 0;
}

body:is([data-path="login"], [data-path="update-password"]) .login-content.page-card {
	width: 100%;
	max-width: var(--kyc-card-w);
	margin: 0 auto;
	padding: 28px 30px 30px;
	background: var(--kyc-surface);
	border: 1px solid var(--kyc-line);
	border-radius: 28px;
	box-shadow: 0 16px 34px rgba(46, 43, 37, 0.13), inset 0 1px 0 rgba(255, 255, 255, 0.9);
}

body:is([data-path="login"], [data-path="update-password"]) .page-card-body {
	padding: 0;
}

/* Narrow screens never get the panel, so they never get what is in it: without
 * this the injected column would fall into the page above the card. Hidden by
 * default and turned on inside the min-width block, so there is no band of
 * fractional widths — routine under OS scaling and browser zoom — where neither
 * rule applies and the panel's contents land unstyled at the end of the page. */
body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-panel {
	display: none;
}

/* -------------------------------------------------------------- panel ----- */

/* Wide enough for two columns: the brand takes the left, the form the right.
 * The panel is fixed rather than laid out, so it cannot be pushed around by
 * whichever of the six sections (sign in, forgot, email link, sign up…) the
 * page happens to be showing. */
@media (min-width: 900px) {
	body:is([data-path="login"], [data-path="update-password"]) {
		--kyc-panel-w: clamp(340px, 42vw, 620px);
		--kyc-panel-pad: clamp(40px, 4.5vw, 76px);
		/* The mark's size and where it sits, named once: the wordmark is placed
		 * under it and the step list under that, and each of them has to know
		 * exactly how tall the thing above it turned out to be. */
		--kyc-mark: 60px;
		--kyc-mark-top: clamp(56px, 11vh, 108px);
		--kyc-wordmark: clamp(30px, 3.1vw, 42px);
	}

	/* The panel's surface: clay, a lit corner, and a quiet weave so it reads as a
	 * material rather than a fill. Nothing is drawn on it here — the mark used to
	 * be a background layer on this rule, which meant it painted at the top of the
	 * panel the moment the stylesheet landed and then jumped to the middle when
	 * the script's own column arrived. The surface does not move, so the surface
	 * is all this paints. */
	body:is([data-path="login"], [data-path="update-password"])::before {
		content: "";
		position: fixed;
		inset: 0 auto 0 0;
		width: var(--kyc-panel-w);
		border-radius: 0 44px 44px 0;
		background: repeating-linear-gradient(
				62deg,
				rgba(255, 255, 255, 0.045) 0 2px,
				transparent 2px 9px
			),
			radial-gradient(120% 85% at 12% 8%, rgba(255, 246, 236, 0.14), transparent 58%),
			/* Deeper than it was, and the bloom over it lighter: the panel carries
			 * every word on this half of the page, and cream on the old #c67139 top
			 * stop read 2.9:1 — under the floor for the wordmark, let alone for the
			 * step list. Cream on these stops runs 4.6:1 at the lit corner to
			 * 10.2:1 at the foot. */
			linear-gradient(158deg, #8c491a 0%, #7a3d14 46%, #5d300e 100%);
		box-shadow: 24px 0 54px rgba(96, 51, 18, 0.22), inset -1px 0 0 rgba(255, 255, 255, 0.14);
	}

	/* ---- what the panel says, with no script to say it ------------------- */

	/* The mark and the wordmark as one block, and the strapline at the foot.
	 * Both wait a fifth of a second before they appear: kyc_login.js replaces
	 * them with a centred column, and on a page where the script is coming, this
	 * is what would otherwise be seen arriving and then moving. Where the script
	 * never comes, a fifth of a second is not a wait anyone notices. */
	body:not(.kyc-panel-live):is([data-path="login"], [data-path="update-password"])::after {
		content: "Identity\A Verification";
		white-space: pre;
		position: fixed;
		left: var(--kyc-panel-pad);
		top: var(--kyc-mark-top);
		padding-top: calc(var(--kyc-mark) + 26px);
		background: url("/assets/kyc_integration/images/kyc-mark.svg") no-repeat left top /
			var(--kyc-mark) var(--kyc-mark);
		font-family: "Caprasimo", "Figtree", system-ui, sans-serif;
		font-weight: 400;
		font-size: var(--kyc-wordmark);
		line-height: 1.06;
		letter-spacing: -0.02em;
		color: #fdf3e6;
		text-shadow: 0 3px 14px rgba(58, 27, 6, 0.34);
		animation: kyc-fade 0.5s ease 0.2s both;
	}

	body:not(.kyc-panel-live):is([data-path="login"], [data-path="update-password"]) section::before {
		content: "A document, a face and a live person, checked in one pass — with every step kept for whoever audits it.";
		position: fixed;
		left: var(--kyc-panel-pad);
		bottom: clamp(40px, 7vh, 76px);
		width: calc(var(--kyc-panel-w) - var(--kyc-panel-pad) * 2);
		max-width: 400px;
		padding-top: 18px;
		border-top: 1px solid rgba(255, 240, 224, 0.28);
		font-size: 14.5px;
		line-height: 1.55;
		color: rgba(255, 243, 232, 0.92);
		animation: kyc-fade 0.5s ease 0.25s both;
	}

	/* The form keeps the ground to the right of the panel. */
	body:is([data-path="login"], [data-path="update-password"]) .page-content-wrapper {
		margin-left: var(--kyc-panel-w);
	}

	/* The mark and the eyebrow are on the panel now; a second set inside the card
	 * would be the same two things said twice, a hand's width apart. */
	body:is([data-path="login"], [data-path="update-password"]) .page-card-head::before,
	body:is([data-path="login"], [data-path="update-password"]) .page-card-head::after {
		content: none;
	}

	body:is([data-path="login"], [data-path="update-password"]) .page-card-head h4 {
		font-size: 30px;
	}

	body:is([data-path="login"], [data-path="update-password"]) {
		--kyc-card-w: 408px;
	}

	body:is([data-path="login"], [data-path="update-password"]) .login-content.page-card {
		padding: 34px 34px 32px;
	}

	/* ---- the panel, as one block ---------------------------------------- */

	/* Everything the panel says, in a column that stands in the middle of it.
	 * Pinning each piece to an edge — which is all the pseudo-elements below can
	 * do — leaves a tall screen empty down the middle; this is the same content,
	 * grouped, so the panel reads the same at 700px as at 2000px. */
	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-panel {
		display: flex;
		position: fixed;
		inset: 0 auto 0 0;
		z-index: 1;
		flex-direction: column;
		justify-content: center;
		gap: 26px;
		width: var(--kyc-panel-w);
		padding: clamp(36px, 6vh, 76px) var(--kyc-panel-pad);
		color: #fdf3e6;
	}

	/* The lean towards the pointer is a transform, not the `translate` property:
	 * the entrance keyframes animate `translate`, and an animation's final
	 * keyframe outranks any author declaration for the property it animates —
	 * which quietly held three of these four pieces still. */
	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-mark {
		width: var(--kyc-mark);
		height: var(--kyc-mark);
		filter: drop-shadow(0 12px 22px rgba(58, 27, 6, 0.35));
		transform: translate(calc(var(--kyc-par-x, 0px) * 0.6), calc(var(--kyc-par-y, 0px) * 0.6));
		transition: transform 0.5s cubic-bezier(0.2, 0.7, 0.3, 1);
		animation: kyc-fade 0.6s ease 0.28s both;
	}

	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-word {
		margin: 0;
		font-family: "Caprasimo", "Figtree", system-ui, sans-serif;
		font-weight: 400;
		font-size: var(--kyc-wordmark);
		line-height: 1.06;
		letter-spacing: -0.02em;
		text-shadow: 0 3px 14px rgba(58, 27, 6, 0.34);
		transform: translate(calc(var(--kyc-par-x, 0px) * 0.4), calc(var(--kyc-par-y, 0px) * 0.4));
		transition: transform 0.5s cubic-bezier(0.2, 0.7, 0.3, 1);
		animation: kyc-fade 0.6s ease 0.36s both;
	}

	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-strap {
		max-width: 400px;
		margin: 0;
		padding-top: 18px;
		border-top: 1px solid rgba(255, 240, 224, 0.28);
		font-size: 14.5px;
		line-height: 1.55;
		color: rgba(255, 243, 232, 0.92);
		transform: translate(calc(var(--kyc-par-x, 0px) * 0.22), calc(var(--kyc-par-y, 0px) * 0.22));
		transition: transform 0.6s cubic-bezier(0.2, 0.7, 0.3, 1);
		animation: kyc-fade 0.6s ease 0.6s both;
	}

	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-steps {
		width: 100%;
		max-width: 400px;
		margin: 0;
		padding: 0;
		list-style: none;
		transform: translate(calc(var(--kyc-par-x, 0px) * 0.3), calc(var(--kyc-par-y, 0px) * 0.3));
		transition: transform 0.55s cubic-bezier(0.2, 0.7, 0.3, 1);
	}

	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-step {
		display: flex;
		align-items: flex-start;
		gap: 12px;
		padding: 9px 12px 9px 10px;
		border-radius: 14px;
		color: rgba(255, 243, 232, 0.82);
		transition: color 0.45s ease, background-color 0.45s ease, transform 0.45s cubic-bezier(0.2, 0.7, 0.3, 1);
		/* The script inserts the list after the page has painted, so the arrival
		 * plays on insertion; each step follows the one above it. */
		animation: kyc-fade 0.5s cubic-bezier(0.2, 0.8, 0.3, 1) both;
		animation-delay: calc(0.44s + var(--i) * 0.08s);
	}

	/* The step being spoken about: lit, on a pane of its own. */
	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-step.is-on {
		color: #fff6ec;
		background: rgba(255, 243, 232, 0.16);
		box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16);
		transform: translateX(4px);
	}

	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-step__dot {
		position: relative;
		flex: 0 0 auto;
		width: 9px;
		height: 9px;
		margin-top: 5px;
		border-radius: 50%;
		background: rgba(255, 243, 232, 0.62);
		transition: background-color 0.35s ease;
	}

	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-step.is-on .kyc-signin-step__dot {
		background: #ffe9d2;
	}

	/* The halo only exists on the lit step, so it cannot pulse four at once. */
	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-step.is-on .kyc-signin-step__dot::after {
		content: "";
		position: absolute;
		inset: -5px;
		border-radius: 50%;
		border: 1px solid rgba(255, 233, 210, 0.55);
		animation: kyc-signin-pulse 2.4s ease-out infinite;
	}

	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-step__text {
		display: block;
		min-width: 0;
	}

	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-step__text b {
		display: block;
		font-size: 14px;
		font-weight: 600;
		line-height: 1.3;
	}

	/* The second line belongs to the step being spoken about; on the others it
	 * would be four paragraphs competing for one glance. */
	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-step__text em {
		display: block;
		max-height: 0;
		overflow: hidden;
		font-size: 12.5px;
		font-style: normal;
		line-height: 1.5;
		opacity: 0;
		transition: max-height 0.4s ease, opacity 0.3s ease, margin-top 0.4s ease;
	}

	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-step.is-on .kyc-signin-step__text em {
		max-height: 3.4em;
		margin-top: 2px;
		opacity: 0.78;
	}

	/* Rotation off: the list is just a list, and every line stands open. */
	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-steps.is-static .kyc-signin-step__text em {
		max-height: 3.4em;
		margin-top: 2px;
		opacity: 0.7;
	}
}

@keyframes kyc-signin-pulse {
	0% {
		transform: scale(0.8);
		opacity: 0.9;
	}
	70% {
		transform: scale(2.1);
		opacity: 0;
	}
	100% {
		transform: scale(2.1);
		opacity: 0;
	}
}

/* A window shorter than the column is tall gives up the middle of it — the mark,
 * the wordmark and the strapline still say what the panel is for. */
@media (max-height: 560px) {
	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-steps {
		display: none;
	}
}

/* ------------------------------------------------------------- chrome ----- */

/* The way back out. Fixed to the corner rather than placed in the card: it
 * belongs to the page, not to the form, and the form is the only thing on this
 * page a reader should have to look at twice. */
body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-back {
	position: fixed;
	top: 22px;
	right: 26px;
	z-index: 5;
	display: inline-flex;
	align-items: center;
	gap: 7px;
	padding: 8px 16px;
	border-radius: 999px;
	font-size: 13px;
	font-weight: 600;
	color: var(--kyc-ink-3);
	background: color-mix(in srgb, var(--kyc-surface) 80%, transparent);
	border: 1px solid color-mix(in srgb, var(--kyc-line) 80%, transparent);
	backdrop-filter: blur(10px);
	-webkit-backdrop-filter: blur(10px);
	transition: color 0.2s ease, border-color 0.2s ease, transform 0.2s ease,
		background-color 0.2s ease;
	animation: kyc-rise 0.5s ease 0.45s both;
}

body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-back:hover {
	color: var(--kyc-brand-700);
	background: var(--kyc-surface);
	border-color: #d9c9a9;
	text-decoration: none;
	transform: translateX(-2px);
}

body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-back span {
	transition: transform 0.2s ease;
}

body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-back:hover span {
	transform: translateX(-3px);
}

/* The note under the card, for the applicant who followed a verification link
 * into the wrong tab and is now being asked for a password they never had. */
body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-aside {
	width: min(var(--kyc-card-w), 100%);
	margin: 18px auto 0;
	padding: 15px 18px;
	border-radius: 20px;
	border: 1px dashed color-mix(in srgb, var(--kyc-line) 90%, var(--kyc-brand));
	background: color-mix(in srgb, var(--kyc-surface) 55%, transparent);
	animation: kyc-rise 0.5s cubic-bezier(0.2, 0.85, 0.3, 1) 0.46s both;
}

body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-aside b {
	display: block;
	font-size: 13px;
	font-weight: 600;
	color: var(--kyc-ink);
}

body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-aside span {
	display: block;
	margin-top: 4px;
	font-size: 12.5px;
	line-height: 1.55;
	color: var(--kyc-ink-3);
}

/* The seal the service signs its pages with, the same one the landing page
 * carries, under the form rather than beside it: it says who stands behind the
 * page without competing with the one thing on it to be filled in. */
body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-foot {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 7px;
	margin: 22px 0 0;
	text-align: center;
	font-size: 11.5px;
	letter-spacing: 0.04em;
	color: var(--kyc-ink-3);
	animation: kyc-rise 0.5s ease 0.55s both;
	pointer-events: none;
}

body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-foot img {
	box-sizing: content-box;
	height: clamp(46px, 5vw, 72px);
	width: auto;
	opacity: 0.9;
	/* The artwork is on white; the ground here is warm, so it is set on its own
	 * plate rather than left to sit in a pale rectangle. */
	padding: 10px 20px;
	border-radius: 18px;
	background: #fffaf1;
	border: 1px solid color-mix(in srgb, var(--kyc-line) 70%, transparent);
	box-shadow: 0 6px 14px rgba(46, 43, 37, 0.08);
}

/* Given the room, the seal leaves the column and takes the foot of the page.
 * Both conditions matter: on a window shorter than the column needs, a fixed,
 * opaque plate paints over the bottom of the card it was meant to sit under, so
 * below that height it stays in the flow and simply follows the note. The column
 * gives back the strip at each end, so the form centres between them. */
@media (min-width: 576px) and (min-height: 760px) {
	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-foot {
		position: fixed;
		left: 0;
		right: 0;
		bottom: 16px;
		margin: 0;
	}

	body:is([data-path="login"], [data-path="update-password"]) .page-content-wrapper {
		padding-top: 72px;
		padding-bottom: 148px;
	}
}

@media (min-width: 900px) {
	/* Both belong to the form's half of the page, so neither strays over the
	 * panel. */
	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-foot {
		left: var(--kyc-panel-w);
	}

}

/* ------------------------------------------------------------- motion ----- */

/* The entrance is animation, not a class the script toggles: web_include_js is
 * served at the end of the body, so anything JavaScript-gated would have to
 * hide a card the browser has already painted — a flash on every sign-in, and a
 * blank card for anyone whose script never arrives. Keyframes run at first
 * paint and need nobody's help. */
@keyframes kyc-rise {
	from {
		opacity: 0;
		translate: 0 14px;
	}
	to {
		opacity: 1;
		translate: 0 0;
	}
}

@keyframes kyc-wipe {
	from {
		clip-path: inset(0 100% 0 0 round 0 44px 44px 0);
	}
	to {
		clip-path: inset(0 0 0 0 round 0 44px 44px 0);
	}
}

@keyframes kyc-fade {
	from {
		opacity: 0;
		translate: -12px 0;
	}
	to {
		opacity: 1;
		translate: 0 0;
	}
}

body:is([data-path="login"], [data-path="update-password"]) .login-content.page-card {
	animation: kyc-rise 0.6s cubic-bezier(0.2, 0.85, 0.3, 1) both;
	transition: box-shadow 0.3s ease;
}

/* The card's own contents arrive after it, a beat apart, top to bottom. */
body:is([data-path="login"], [data-path="update-password"]) .page-card-head,
body:is([data-path="login"], [data-path="update-password"]) .page-card-body .form-group,
body:is([data-path="login"], [data-path="update-password"]) .page-card-actions,
body:is([data-path="login"], [data-path="update-password"]) .sign-up-message {
	animation: kyc-rise 0.5s cubic-bezier(0.2, 0.85, 0.3, 1) both;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card-head {
	animation-delay: 0.12s;
}
/* Counted as siblings, not by type: the framework puts a <div> banner ahead of
 * the fields, so :nth-of-type(1) matched nothing at all and the password field —
 * falling through to the base rule's zero delay — arrived first. */
body:is([data-path="login"], [data-path="update-password"]) .page-card-body .form-group {
	animation-delay: 0.19s;
}
body:is([data-path="login"], [data-path="update-password"]) .page-card-body .form-group + .form-group {
	animation-delay: 0.26s;
}
body:is([data-path="login"], [data-path="update-password"]) .page-card-actions {
	animation-delay: 0.33s;
}
body:is([data-path="login"], [data-path="update-password"]) .sign-up-message {
	animation-delay: 0.4s;
}

/* The framework shakes the card on a refused password by adding .invalid-login
 * — an animation this file's own entrance rule outranks, so the shake silently
 * stopped happening. Restated here at a chain that wins, reusing the
 * framework's own keyframes. */
body:is([data-path="login"], [data-path="update-password"]) .login-content.page-card.invalid-login {
	animation: wiggle 0.4s ease-in-out;
}

/* The card lifts a little under the pointer — the same clay, held closer. */
body:is([data-path="login"], [data-path="update-password"]) .login-content.page-card:hover {
	box-shadow: 0 22px 44px rgba(46, 43, 37, 0.16), inset 0 1px 0 rgba(255, 255, 255, 0.9);
}

@media (min-width: 900px) {
	/* The panel wipes in from its own edge, and its words follow it. */
	body:is([data-path="login"], [data-path="update-password"])::before {
		animation: kyc-wipe 0.75s cubic-bezier(0.3, 0.9, 0.25, 1) both;
	}

	body:is([data-path="login"], [data-path="update-password"])::after {
		animation: kyc-fade 0.6s ease 0.3s both;
	}

	body:is([data-path="login"], [data-path="update-password"]) section::before {
		animation: kyc-fade 0.6s ease 0.55s both;
	}
}

/* -------------------------------------------------------------- fields ---- */

/* Frappe's login stylesheet reaches these inputs through five-class chains
 * (".for-login .page-card .page-card-body .password-field input") for the
 * background, the icon inset and the Show toggle. A short selector loses the
 * cascade to them however well scoped it is, so the contested rules below climb
 * to the same shape — body[data-path] + the same chain — and win by one element.
 * Anything not contested is set once on .form-control above.
 *
 * The chain deliberately omits ".for-*", so one rule covers sign-in, forgot
 * password and email-link alike.
 */

/* Inputs read as pressed wells in the clay, the same shape the desk uses for
 * its search bar and score meters. */
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .email-field input,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .password-field input {
	height: 46px;
	padding: 0 16px 0 44px;
	font-size: 14px;
	color: var(--kyc-ink);
	background: var(--kyc-bg);
	border: 1px solid transparent;
	border-radius: 999px;
	box-shadow: inset 0 2px 5px rgba(46, 43, 37, 0.13), inset 0 -2px 4px rgba(255, 255, 255, 0.75);
	caret-color: var(--kyc-brand);
	transition: border-color 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
}

/* The password box is the one with a control inside its right edge; the caret
 * has to stop before the eye rather than run under it. */
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .password-field input {
	padding-right: 44px;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .email-field input::placeholder,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .password-field input::placeholder {
	color: var(--kyc-ink-3);
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .email-field input:focus,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .password-field input:focus {
	background: var(--kyc-surface);
	border-color: var(--kyc-brand);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--kyc-brand) 22%, transparent);
	outline: none;
}

/* The icon warms up once the box beside it holds something, so a glance says
 * which field is still empty without reading either of them. */
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .field-icon {
	transition: fill 0.25s ease, transform 0.25s cubic-bezier(0.2, 1.4, 0.4, 1);
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .has-value .field-icon,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .email-field:focus-within .field-icon,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .password-field:focus-within .field-icon {
	fill: var(--kyc-brand);
	transform: translateY(-50%) scale(1.08);
}

/* The Show/Hide eye is the one control in the form that is pressed rather than
 * typed into, so it answers to the pointer. */
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .toggle-password {
	transition: fill 0.2s ease, transform 0.2s cubic-bezier(0.2, 1.4, 0.4, 1);
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .toggle-password:hover {
	fill: var(--kyc-brand-700);
	transform: translateY(-50%) scale(1.14);
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .toggle-password:active {
	transform: translateY(-50%) scale(0.94);
}

/* Caps Lock, said while the password is being typed rather than after it is
 * refused. kyc_login.js inserts this and only ever toggles .is-on. */
body:is([data-path="login"], [data-path="update-password"]) .kyc-caps-hint {
	display: flex;
	align-items: center;
	gap: 6px;
	max-height: 0;
	margin: 0;
	overflow: hidden;
	font-size: 12px;
	font-weight: 600;
	color: var(--kyc-brand-700);
	opacity: 0;
	transition: max-height 0.25s ease, opacity 0.2s ease, margin-top 0.25s ease;
}

body:is([data-path="login"], [data-path="update-password"]) .kyc-caps-hint::before {
	content: "\2191";
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 15px;
	height: 15px;
	border-radius: 5px;
	background: color-mix(in srgb, var(--kyc-brand) 22%, transparent);
	font-size: 10px;
	line-height: 1;
}

body:is([data-path="login"], [data-path="update-password"]) .kyc-caps-hint.is-on {
	max-height: 2em;
	margin-top: 2px;
	opacity: 1;
}

/* Chrome and Safari paint an autofilled box in their own pale blue, over the
 * clay well and through it — the one part of this form the theme does not get to
 * decide. The inset shadow is the only way to reach that layer; the paired
 * text-fill-colour keeps the value legible on top of it. */
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body input:-webkit-autofill,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body input:-webkit-autofill:hover,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body input:-webkit-autofill:focus {
	-webkit-text-fill-color: var(--kyc-ink);
	caret-color: var(--kyc-brand);
	box-shadow: inset 0 0 0 40px var(--kyc-bg), inset 0 2px 5px rgba(46, 43, 37, 0.13);
	/* The fill is applied on a transition, so a long one never arrives. */
	transition: background-color 100000s ease 0s;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body input:-webkit-autofill:focus {
	box-shadow: inset 0 0 0 40px var(--kyc-surface),
		0 0 0 3px color-mix(in srgb, var(--kyc-brand) 22%, transparent);
}

/* What the form says when it refuses. Frappe's banners are its own greys and
 * reds; these are the same two states in this page's palette. */
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .login-error-banner {
	padding: 9px 13px;
	border-radius: 14px;
	font-size: 13px;
	color: #8a2f22;
	background: #fbe6df;
	border: 1px solid #f0cabc;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .login-error-banner svg {
	fill: #b23f2c;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .login-success-banner {
	padding: 9px 13px;
	border-radius: 14px;
	font-size: 13px;
	color: #3f5c2c;
	background: #e8f0dc;
	border: 1px solid #cfdfba;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .login-success-banner svg {
	fill: #4f7238;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .field-error {
	font-size: 12.5px;
	color: #b23f2c;
}

/* Every focusable thing on the page answers a keyboard the same way. */
body:is([data-path="login"], [data-path="update-password"]) a:focus-visible,
body:is([data-path="login"], [data-path="update-password"]) .page-card .btn:focus-visible,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .toggle-password:focus-visible {
	outline: 2px solid var(--kyc-brand);
	outline-offset: 3px;
	border-radius: 999px;
}

body:is([data-path="login"], [data-path="update-password"]) .email-field,
body:is([data-path="login"], [data-path="update-password"]) .password-field {
	position: relative;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .field-icon {
	position: absolute;
	top: 50%;
	left: 17px;
	transform: translateY(-50%);
	/* fill, not color: these are <use> references into the framework's sprite,
	 * whose paths carry no fill of their own and inherit it from the <svg>. A
	 * `color` here is a declaration nothing reads. */
	fill: var(--kyc-ink-4);
	pointer-events: none;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .email-field .toggle-password,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .password-field .toggle-password {
	position: absolute;
	top: 50%;
	right: 18px;
	transform: translateY(-50%);
	fill: var(--kyc-ink-4);
	cursor: pointer;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .password-field .toggle-password:hover {
	fill: var(--kyc-brand-700);
}

body:is([data-path="login"], [data-path="update-password"]) .forgot-password-message {
	margin: 10px 2px 0;
	text-align: right;
	font-size: 12.5px;
}

body:is([data-path="login"], [data-path="update-password"]) a {
	color: var(--kyc-brand-700);
	text-decoration: none;
}

body:is([data-path="login"], [data-path="update-password"]) a:hover {
	color: var(--kyc-brand-600);
	text-decoration: underline;
}

/* The two ways out of the form — "Forgot password?" and "Back to sign in" —
 * are painted grey by longer framework chains than a bare `a` can outrank. */
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .forgot-password-message > *,
body:is([data-path="login"], [data-path="update-password"]) .page-card .sign-up-message a {
	color: var(--kyc-brand-700);
	font-weight: 500;
	text-decoration: none;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body .forgot-password-message > *:hover,
body:is([data-path="login"], [data-path="update-password"]) .page-card .sign-up-message a:hover {
	color: var(--kyc-brand-600);
	text-decoration: underline;
}

/* ------------------------------------------------------------- actions ---- */

/* Frappe v16 paints these through ".for-login .page-card .page-card-actions
 * .btn-login" — four classes, which a two-class rule loses to per property: the
 * font below was ours and the flat black behind it was theirs. The chains here
 * match that shape, and the attribute selector on body puts them one ahead.
 * ".btn-signup" is the same button on the forgot-password and sign-up states. */
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-login,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-ldap-login,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-signup,
/* v16 styles this one through ".btn-signup:not(:disabled)", and :not() counts
 * its argument — so the enabled "Send Link" and "Create Account" kept the pill,
 * the font and the shadow from here and took their near-black fill from there.
 * One more class in the chain and they are whole. */
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-signup:not(:disabled),
body:is([data-path="login"], [data-path="update-password"]) .page-card-actions .btn-primary {
	height: 46px;
	font-family: "Caprasimo", "Figtree", system-ui, sans-serif;
	font-weight: 400;
	font-size: 15px;
	letter-spacing: 0.01em;
	color: #fdf6ea;
	/* Deep enough to carry its own label: the old #d67f48 top stop put the text at
	 * 2.80:1, under a contrast floor of 4.5. These stops read 5.14:1 at the top
	 * and 8.84:1 at the foot, and the button is the same clay it always was. */
	background: linear-gradient(160deg, #a1541f, #6c3811);
	border: 0;
	border-radius: 999px;
	box-shadow: 0 10px 18px rgba(140, 73, 26, 0.3), inset 0 -4px 8px rgba(64, 35, 16, 0.25),
		inset 0 4px 8px rgba(255, 255, 255, 0.22);
	transition: box-shadow 0.15s ease, transform 0.05s ease;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-login:hover,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-login:focus,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-ldap-login:hover,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-signup:not(:disabled):hover,
body:is([data-path="login"], [data-path="update-password"]) .page-card-actions .btn-primary:hover {
	/* Lifted, not lightened: brightening the gradient on hover — and, as it was
	 * written, on focus — walked the label back under the contrast floor at the
	 * exact moment a keyboard user arrived on it. */
	color: #fdf6ea;
	background: linear-gradient(160deg, #ac5b23, #743d13);
	border: 0;
	/* Restated, because the framework's own hover rule sets box-shadow: none and
	 * would otherwise flatten the button the moment a pointer touched it. */
	box-shadow: 0 14px 24px rgba(140, 73, 26, 0.34), inset 0 -4px 8px rgba(64, 35, 16, 0.25),
		inset 0 4px 8px rgba(255, 255, 255, 0.22);
}

/* The framework disables and relabels these buttons on success ("Sent"), and
 * paints that state black. It is the last thing the screen says before the mail
 * arrives, so it stays in the page's own colour. */
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-login:disabled,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-login-option:disabled {
	color: #fdf6ea;
	background: linear-gradient(160deg, #a1541f, #6c3811);
	opacity: 0.72;
	box-shadow: none;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-login:active,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-ldap-login:active,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-signup:not(:disabled):active,
body:is([data-path="login"], [data-path="update-password"]) .page-card-actions .btn-primary:active {
	transform: translateY(1px);
	box-shadow: 0 5px 10px rgba(140, 73, 26, 0.28), inset 0 4px 9px rgba(64, 35, 16, 0.3);
}

/* "Send Link" is disabled until the email box has something in it. Sitting there
 * in full brand colour, it looks pressable, which is the one thing it isn't. */
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-signup:disabled {
	color: var(--kyc-ink-4);
	background: var(--kyc-bg);
	box-shadow: inset 0 2px 5px rgba(46, 43, 37, 0.1);
	opacity: 1;
}

/* A press leaves a mark where it landed, and a sheen crosses the button under
 * the pointer. Both are drawn inside the button, which has to clip them. */
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn {
	position: relative;
	overflow: hidden;
	isolation: isolate;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-login::before,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-ldap-login::before,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-signup:not(:disabled)::before {
	content: "";
	position: absolute;
	inset: 0 auto 0 -60%;
	width: 45%;
	background: linear-gradient(100deg, transparent, rgba(255, 240, 225, 0.42), transparent);
	transform: skewX(-18deg);
	transition: left 0.55s cubic-bezier(0.3, 0.8, 0.3, 1);
	pointer-events: none;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-login:hover::before,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-ldap-login:hover::before,
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-signup:not(:disabled):hover::before {
	left: 115%;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-login-option {
	transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease,
		transform 0.12s ease, box-shadow 0.2s ease;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-login-option:hover {
	transform: translateY(-1px);
	box-shadow: 0 10px 18px rgba(46, 43, 37, 0.13), inset 0 2px 6px rgba(255, 255, 255, 0.9);
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-login-option:active {
	transform: translateY(1px);
	box-shadow: inset 0 2px 6px rgba(46, 43, 37, 0.14);
}

body:is([data-path="login"], [data-path="update-password"]) .kyc-ink {
	position: absolute;
	width: 12px;
	height: 12px;
	margin: -6px 0 0 -6px;
	border-radius: 50%;
	background: rgba(255, 246, 236, 0.55);
	pointer-events: none;
	animation: kyc-ink 0.55s cubic-bezier(0.2, 0.7, 0.3, 1) forwards;
}

@keyframes kyc-ink {
	from {
		transform: scale(0.4);
		opacity: 0.7;
	}
	to {
		transform: scale(22);
		opacity: 0;
	}
}

/* Sign-in is a round trip. While it is in the air the button says so and stops
 * inviting a second press against the same password.
 *
 * The label stays. Blanking it to `transparent` and leaving a ring in the middle
 * left the button saying nothing at all — and to a reader who has asked for less
 * motion, where the ring cannot turn, it left an empty pill with a broken circle
 * in it. The ring sits beside the label instead, and becomes a still dot when
 * turning is not allowed. */
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn.is-working {
	padding-right: 42px;
	pointer-events: none;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn.is-working::after {
	content: "";
	position: absolute;
	top: 50%;
	right: 18px;
	width: 16px;
	height: 16px;
	margin-top: -8px;
	border-radius: 50%;
	border: 2px solid rgba(253, 246, 234, 0.35);
	border-top-color: #fdf6ea;
	animation: kyc-spin 0.7s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
	body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn.is-working::after {
		border: 0;
		background: #fdf6ea;
		opacity: 0.85;
	}
}

@keyframes kyc-spin {
	to {
		transform: rotate(360deg);
	}
}

/* Screens this card also shows, reached through the framework's own routing and
 * left in its plain grey until now: the resend line under an emailed link, the
 * "Signups have been disabled" message, and — on the reset-password page — the
 * inputs that sit outside an .email-field / .password-field wrapper. */
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .resend-link {
	font-size: 13px;
	color: var(--kyc-ink-3);
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .resend-link a {
	color: var(--kyc-brand-700);
	font-weight: 500;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .signup-disabled-message .btn-primary {
	height: 44px;
	padding: 0 22px;
	border-radius: 999px;
	color: #fdf6ea;
	background: linear-gradient(160deg, #a1541f, #6c3811);
	border: 0;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body > .form-group > input.form-control {
	height: 46px;
	padding: 0 16px;
	font-size: 14px;
	color: var(--kyc-ink);
	background: var(--kyc-bg);
	border: 1px solid transparent;
	border-radius: 999px;
	box-shadow: inset 0 2px 5px rgba(46, 43, 37, 0.13), inset 0 -2px 4px rgba(255, 255, 255, 0.75);
	caret-color: var(--kyc-brand);
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body > .form-group > input.form-control:focus {
	background: var(--kyc-surface);
	border-color: var(--kyc-brand);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--kyc-brand) 22%, transparent);
	outline: none;
}

/* Two-factor. Frappe builds this step in JavaScript rather than in the template
 * — it empties .login-content and appends a bare input and button — so none of
 * the chains above reach it and it would arrive unstyled in the middle of a
 * styled sign-in. */
body:is([data-path="login"], [data-path="update-password"]) .page-card #twofactor_div .form-control {
	height: 46px;
	padding: 0 18px;
	font-size: 15px;
	letter-spacing: 0.16em;
	text-align: center;
	color: var(--kyc-ink);
	background: var(--kyc-bg);
	border: 1px solid transparent;
	border-radius: 999px;
	box-shadow: inset 0 2px 5px rgba(46, 43, 37, 0.13), inset 0 -2px 4px rgba(255, 255, 255, 0.75);
	caret-color: var(--kyc-brand);
}

body:is([data-path="login"], [data-path="update-password"]) .page-card #twofactor_div .form-control:focus {
	background: var(--kyc-surface);
	border-color: var(--kyc-brand);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--kyc-brand) 22%, transparent);
	outline: none;
}

body:is([data-path="login"], [data-path="update-password"]) .page-card #twofactor_div #verify_token {
	height: 46px;
	margin-top: 14px;
	font-family: "Caprasimo", "Figtree", system-ui, sans-serif;
	font-weight: 400;
	font-size: 15px;
	color: #fdf6ea;
	background: linear-gradient(160deg, #a1541f, #6c3811);
	border: 0;
	border-radius: 999px;
	box-shadow: 0 10px 18px rgba(140, 73, 26, 0.3), inset 0 -4px 8px rgba(64, 35, 16, 0.25),
		inset 0 4px 8px rgba(255, 255, 255, 0.22);
}

/* Email-link and social sign-in: the theme's raised-but-quiet pill. v16 puts
 * the email-link button straight into .page-card-actions and only wraps the
 * social ones in .login-button-wrapper, so the chain matches the actions block
 * itself — which is also where the framework's own grey pill is set. */
body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-login-option {
	height: 44px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	font-size: 14px;
	font-weight: 600;
	color: var(--kyc-ink);
	background: var(--kyc-surface);
	border: 1px solid var(--kyc-line);
	border-radius: 999px;
	box-shadow: 0 7px 14px rgba(46, 43, 37, 0.1), inset 0 2px 6px rgba(255, 255, 255, 0.9);
}

body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-actions .btn-login-option:hover {
	background: #fffaf2;
	/* The whole border, not just its colour: v16's own :hover sets "border: none"
	 * and outranks our unhovered rule, so the outline would vanish under the
	 * pointer if this only named the colour. */
	border: 1px solid #d9c9a9;
	color: var(--kyc-brand-700);
}

body:is([data-path="login"], [data-path="update-password"]) .login-button-wrapper + .login-button-wrapper {
	margin-top: 10px;
}

body:is([data-path="login"], [data-path="update-password"]) .sign-up-message {
	margin-top: 18px;
	font-size: 13px;
	color: var(--kyc-ink-3);
}

/* Frappe paints a few of these states through .text-muted. */
body:is([data-path="login"], [data-path="update-password"]) .text-muted {
	color: var(--kyc-ink-3);
}

/* Phones. The framework turns the card into the whole screen below 576px, which
 * leaves the note under it — the one an applicant who followed a verification
 * link most needs — a scroll away on the device they are most likely to be
 * holding. Keep it a card, and let what belongs under it sit under it. */
@media (max-width: 575.98px) {
	body:is([data-path="login"], [data-path="update-password"]) .page-content-wrapper {
		padding: 26px 16px 30px;
	}

	body:is([data-path="login"], [data-path="update-password"]) .login-content.page-card {
		min-height: auto;
		border-radius: 26px;
		border: 1px solid var(--kyc-line);
	}

	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-back {
		top: 14px;
		right: 14px;
		padding: 7px 13px;
		font-size: 12px;
	}

}

@media (max-width: 480px) {
	body:is([data-path="login"], [data-path="update-password"]) .login-content.page-card {
		padding: 24px 20px 26px;
		border-radius: 24px;
	}
	body:is([data-path="login"], [data-path="update-password"]) .page-card-head::before {
		width: 72px;
		height: 72px;
	}
	body:is([data-path="login"], [data-path="update-password"]) .page-card-head h4 {
		font-size: 24px;
	}
}

/* ----------------------------------------------------------- stillness ---- */

/* Asked for less motion, the page keeps every state it can show without moving:
 * the panel, the lit step, the caps-lock hint and the pressed button all still
 * read — they simply arrive rather than travel. kyc_login.js makes the same
 * choice for the parts it owns (no rotation, no parallax, no press ink). */
@media (prefers-reduced-motion: reduce) {
	body:is([data-path="login"], [data-path="update-password"]),
	body:is([data-path="login"], [data-path="update-password"]) *,
	body:is([data-path="login"], [data-path="update-password"])::before,
	body:is([data-path="login"], [data-path="update-password"])::after,
	body:is([data-path="login"], [data-path="update-password"]) *::before,
	body:is([data-path="login"], [data-path="update-password"]) *::after {
		animation-duration: 0.001s !important;
		animation-delay: 0s !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.001s !important;
		transition-delay: 0s !important;
	}
}

/* ------------------------------------------------------------- at night -- */

/* The landing page has answered prefers-color-scheme since it was written, and
 * the desk theme has a dark palette of its own; sign-in was the one screen in
 * between still burning a cream page at 2am. Same room, lights off: the ground
 * and the card go to warm charcoal, the clay panel keeps its colour (it is the
 * one lit thing on the page, and it is what the mark is drawn against), and the
 * ink inverts. Every value below is a token this file already reads, bar the
 * five hard-coded plates — the banners, the seal's plate, the autofill fill —
 * which are named again here because they were written as literals.
 *
 * color-scheme tells the engine to give this page dark form controls, dark
 * scrollbars and a dark autofill shade, which is the half of this a stylesheet
 * cannot reach on its own. */
@media (prefers-color-scheme: dark) {
	body:is([data-path="login"], [data-path="update-password"]) {
		--kyc-brand: #dd8b4e;
		--kyc-brand-600: #e09a63;
		--kyc-brand-700: #efb98c;
		--kyc-bg: #17130f;
		--kyc-surface: #221c17;
		--kyc-ink: #f6ece0;
		--kyc-ink-3: #bcae9d;
		--kyc-ink-4: #97897a;
		--kyc-line: #3a3129;

		color-scheme: dark;
		background: radial-gradient(1100px 620px at 50% -12%, #201a15, var(--kyc-bg) 62%) no-repeat;
		background-color: var(--kyc-bg);
	}

	/* The wells are cut into the card rather than raised out of it, so at night
	 * they are darker than the surface, not lighter. */
	body:is([data-path="login"], [data-path="update-password"])
		.page-card
		.page-card-body
		.email-field
		input,
	body:is([data-path="login"], [data-path="update-password"])
		.page-card
		.page-card-body
		.password-field
		input,
	body:is([data-path="login"], [data-path="update-password"])
		.page-card
		#twofactor_div
		.form-control {
		background: #17130f;
		box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.45), inset 0 -1px 0 rgba(255, 255, 255, 0.04);
	}

	body:is([data-path="login"], [data-path="update-password"])
		.page-card
		.page-card-body
		input:-webkit-autofill,
	body:is([data-path="login"], [data-path="update-password"])
		.page-card
		.page-card-body
		input:-webkit-autofill:hover,
	body:is([data-path="login"], [data-path="update-password"])
		.page-card
		.page-card-body
		input:-webkit-autofill:focus {
		-webkit-text-fill-color: var(--kyc-ink);
		box-shadow: inset 0 0 0 40px #17130f, inset 0 2px 5px rgba(0, 0, 0, 0.45);
	}

	body:is([data-path="login"], [data-path="update-password"]) .login-content.page-card {
		box-shadow: 0 18px 40px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.05);
	}

	body:is([data-path="login"], [data-path="update-password"]) .login-content.page-card:hover {
		box-shadow: 0 24px 52px rgba(0, 0, 0, 0.58), inset 0 1px 0 rgba(255, 255, 255, 0.06);
	}

	/* The two banners, restated: they were written as literal plates because the
	 * palette has no red or green of its own. */
	body:is([data-path="login"], [data-path="update-password"])
		.page-card
		.page-card-body
		.login-error-banner {
		color: #ffb4a2;
		background: #3a1f1a;
		border-color: #55302a;
	}

	body:is([data-path="login"], [data-path="update-password"])
		.page-card
		.page-card-body
		.login-error-banner
		svg {
		fill: #ff9d86;
	}

	body:is([data-path="login"], [data-path="update-password"])
		.page-card
		.page-card-body
		.login-success-banner {
		color: #c8dfa8;
		background: #23301c;
		border-color: #38472c;
	}

	body:is([data-path="login"], [data-path="update-password"])
		.page-card
		.page-card-body
		.login-success-banner
		svg {
		fill: #b7d492;
	}

	body:is([data-path="login"], [data-path="update-password"]) .page-card .page-card-body
		.field-error {
		color: #ff9d86;
	}

	/* The seal is artwork on white and stays on a light plate — dimmed, so it
	 * does not glare out of a dark page. */
	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-foot img {
		opacity: 0.7;
		background: #efe6d8;
		border-color: rgba(255, 255, 255, 0.08);
	}

	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-back {
		background: color-mix(in srgb, var(--kyc-surface) 82%, transparent);
	}

	body:is([data-path="login"], [data-path="update-password"]) .kyc-signin-aside {
		background: color-mix(in srgb, var(--kyc-surface) 60%, transparent);
	}
}


/* ---------------------------------------------------------- signing in ---
 * A successful sign-in is held on one screen: a full-screen frosted sheet
 * over the page just filled in — the card and the clay panel blurred behind
 * it, the service's mark, the wordmark and "Signing you in…" on top — which
 * stays until the desk's first paint replaces the document. kyc_login.js
 * raises the sheet and holds off the framework's body wipe, which is what
 * leaves something behind the blur to blur.
 *
 * The .splash rules further down are the fallback, and are still worth having:
 * they restyle the framework's own splash element into the same room, for the
 * sign-in where the wipe could not be held off — and for the one where this
 * script never ran, which a stylesheet cannot know and does not need to.
 */

body:is([data-path="login"], [data-path="update-password"]) .kyc-splash {
	position: fixed;
	inset: 0;
	/* Over everything this file places: the panel sits at 1, the way back out
	 * at 5, and the framework's own card carries no z-index at all. */
	z-index: 100;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	padding: 24px;
	/* A veil as well as a blur. Blurred alone, the card underneath stays legible
	 * enough to read as a page that has stopped responding rather than one that
	 * is finished with. */
	background: color-mix(in srgb, var(--kyc-bg) 58%, transparent);
	backdrop-filter: blur(26px) saturate(115%);
	-webkit-backdrop-filter: blur(26px) saturate(115%);
	animation: kyc-splash-in 0.34s ease both;
}

/* Where the backdrop cannot be filtered, the veil closes up instead: frosted
 * glass that is not frosting anything is just a smear over a legible form. */
@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
	body:is([data-path="login"], [data-path="update-password"]) .kyc-splash {
		background: color-mix(in srgb, var(--kyc-bg) 95%, transparent);
	}
}

body:is([data-path="login"], [data-path="update-password"]) .kyc-splash__mark {
	width: 96px;
	height: 96px;
	filter: drop-shadow(0 18px 34px rgba(140, 73, 26, 0.3));
	animation: kyc-splash-breathe 1.9s ease-in-out infinite;
}

body:is([data-path="login"], [data-path="update-password"]) .kyc-splash__word {
	margin: 22px 0 0;
	font-family: "Caprasimo", "Figtree", system-ui, sans-serif;
	font-weight: 400;
	font-size: 32px;
	line-height: 1.1;
	letter-spacing: -0.015em;
	color: var(--kyc-ink);
}

body:is([data-path="login"], [data-path="update-password"]) .kyc-splash__sub {
	margin: 6px 0 0;
	font-size: 11px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.16em;
	color: var(--kyc-ink-4);
}

body:is([data-path="login"], [data-path="update-password"]) .kyc-splash__say {
	margin: 26px 0 0;
	font-size: 15px;
	letter-spacing: 0.01em;
	color: var(--kyc-ink-3);
}

body:is([data-path="login"], [data-path="update-password"]) .kyc-splash__bar {
	margin-top: 14px;
	width: 136px;
	height: 3px;
	border-radius: 999px;
	background: color-mix(in srgb, var(--kyc-ink-4) 22%, transparent);
	overflow: hidden;
}

/* Indeterminate on purpose: what is being waited on is a document arriving,
 * and nothing on this side of it knows how far along that is. */
body:is([data-path="login"], [data-path="update-password"]) .kyc-splash__bar i {
	display: block;
	width: 40%;
	height: 100%;
	border-radius: inherit;
	background: linear-gradient(90deg, var(--kyc-brand-700), var(--kyc-brand));
	animation: kyc-splash-run 1.3s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}

/* Under the sheet the page recedes rather than leaves: the blur wants
 * something to work on, and a card that has faded out entirely is a blur of an
 * empty ground. Clicks stop here; the tab order is kyc_login.js's half of it,
 * which marks everything but the sheet inert. */
body:is([data-path="login"], [data-path="update-password"]).kyc-signing-in {
	overflow: hidden;
}

body:is([data-path="login"], [data-path="update-password"]).kyc-signing-in .login-content.page-card,
body:is([data-path="login"], [data-path="update-password"]).kyc-signing-in .kyc-signin-panel,
body:is([data-path="login"], [data-path="update-password"]).kyc-signing-in .kyc-signin-back,
body:is([data-path="login"], [data-path="update-password"]).kyc-signing-in .kyc-signin-aside,
body:is([data-path="login"], [data-path="update-password"]).kyc-signing-in .kyc-signin-foot {
	/* The entrance keyframes (fill-mode: both) would otherwise hold these at
	 * full opacity — an animated property outranks a transitioned one. */
	animation: none !important;
	opacity: 0.5;
	transform: scale(0.99);
	transition: opacity 0.3s ease, transform 0.4s cubic-bezier(0.3, 0.7, 0.3, 1);
	pointer-events: none;
}

@keyframes kyc-splash-in {
	from {
		opacity: 0;
		backdrop-filter: blur(0px);
		-webkit-backdrop-filter: blur(0px);
	}
	to {
		opacity: 1;
	}
}

@keyframes kyc-splash-run {
	0% {
		transform: translateX(-110%);
	}
	100% {
		transform: translateX(250%);
	}
}

/* -------------------------------------------------- the splash fallback ---
 * The framework's success handler replaces the whole body with its splash
 * screen and then navigates. When the sheet above is in play that never
 * happens; when it is not, this is what a sign-in shows — the same room, our
 * mark on the cream, one line of text, no white flash and no foreign logo. The
 * panel's painted background is on body::before and survives the swap, so the
 * left half of a wide screen never changes. */
body:is([data-path="login"], [data-path="update-password"]) .splash {
	position: fixed;
	inset: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 14px;
	margin: 0;
	padding: 0;
	width: auto;
	height: auto;
	/* The framework's .centered positions with a translate; ours fills a box. */
	transform: none;
	background: transparent;
	animation: kyc-fade 0.4s ease 0.05s both;
}
/* The framework's logo is not this service's. */
body:is([data-path="login"], [data-path="update-password"]) .splash img {
	display: none;
}
body:is([data-path="login"], [data-path="update-password"]) .splash::before {
	content: "";
	width: 64px;
	height: 64px;
	border-radius: 20px;
	background: url("/assets/kyc_integration/images/kyc-mark.svg") center / 60px no-repeat;
	animation: kyc-splash-breathe 1.6s ease-in-out infinite;
}
body:is([data-path="login"], [data-path="update-password"]) .splash::after {
	content: "Signing you in\2026";
	font-family: 'Figtree', 'Inter', ui-sans-serif, system-ui, sans-serif;
	font-size: 15px;
	color: rgba(61, 47, 35, 0.7);
	letter-spacing: 0.01em;
}
@media (min-width: 900px) {
	/* On the split layout the splash takes the form's half, beside the panel. */
	body:is([data-path="login"], [data-path="update-password"]) .splash {
		left: 50%;
	}
}
@keyframes kyc-splash-breathe {
	0%, 100% { transform: scale(1); opacity: 0.92; }
	50% { transform: scale(1.06); opacity: 1; }
}

/* At night the sheet is the lit thing in a dark room, so it veils a little
 * harder and the mark's shadow stops pretending to be lit from a window. */
@media (prefers-color-scheme: dark) {
	body:is([data-path="login"], [data-path="update-password"]) .kyc-splash {
		background: color-mix(in srgb, var(--kyc-bg) 66%, transparent);
	}
	body:is([data-path="login"], [data-path="update-password"]) .kyc-splash__mark {
		filter: drop-shadow(0 18px 34px rgba(0, 0, 0, 0.55));
	}
}

/* Standing still, the sheet still arrives — it is what tells you the sign-in
 * took — but nothing on it moves, and the bar, which says "still going" by
 * moving, says it by simply being full instead. */
@media (prefers-reduced-motion: reduce) {
	body:is([data-path="login"], [data-path="update-password"]) .kyc-splash,
	body:is([data-path="login"], [data-path="update-password"]) .kyc-splash__mark {
		animation: none;
	}
	body:is([data-path="login"], [data-path="update-password"]) .kyc-splash__bar i {
		width: 100%;
		opacity: 0.55;
		animation: none;
	}
	body:is([data-path="login"], [data-path="update-password"]).kyc-signing-in .login-content.page-card,
	body:is([data-path="login"], [data-path="update-password"]).kyc-signing-in .kyc-signin-panel,
	body:is([data-path="login"], [data-path="update-password"]).kyc-signing-in .kyc-signin-back,
	body:is([data-path="login"], [data-path="update-password"]).kyc-signing-in .kyc-signin-aside,
	body:is([data-path="login"], [data-path="update-password"]).kyc-signing-in .kyc-signin-foot {
		transition: none;
	}
	body:is([data-path="login"], [data-path="update-password"]) .splash,
	body:is([data-path="login"], [data-path="update-password"]) .splash::before {
		animation: none;
	}
}
