/* Login Extender (EXPERIMENTAL) - split-screen chrome around the stock espresso
 * login (Frappe 16.26.0+). Made render-blocking in the login <head> by the
 * scoped base-template override (customization/login_extender.py ->
 * templates/login_split_base.html), and only ever loaded while the split layout
 * is active on /login; otherwise the stock page renders untouched and this file
 * is never referenced.
 *
 * Contract: the split is laid out with CSS, never a JS re-parent. The stock
 * .page-content-wrapper is positioned as the form rail and the server-rendered
 * .lx-panel as the other half, both position:fixed so document source order is
 * irrelevant and first paint is already the split. Every rule is gated on the
 * body.lx-split-active marker (set by extend_login_context); the handful that
 * touch stock elements (.page-content-wrapper, .page-card-head, #mfa-root) are
 * positional only. Espresso variables (--bg-color, --heading-color, ...) are
 * inherited, never redefined. */

body.lx-split-active {
	/* Wrapper-owned tokens (namespaced --lx-*). Declared on the body marker so
	 * both the stock rail (.page-content-wrapper) and the server-rendered chrome
	 * inherit them. On-image colors are fixed, not theme-dependent: the
	 * photograph is mode-neutral. The scrim base is a de-hued near-black so the
	 * wrapper carries no hue opinion. */
	--lx-scrim-base: 12, 13, 14;
	--lx-on-image: #ffffff;
	--lx-on-image-soft: rgba(255, 255, 255, 0.85);
	--lx-panel-fallback: #f3f3f3;
	--lx-rail-w: 480px;
	--lx-rail-gutter: 44px;
	--lx-rail-top: 36px;
	/* Bottom space the centered card reserves so it never sits under the fixed
	 * footer (which is ~one line plus its own --lx-rail-gutter bottom inset). */
	--lx-footer-reserve: 72px;
	/* Extra clearance a footer image needs on top of the base above (its height
	 * plus the gap over the meta line). 0 by default; extend_login_context
	 * writes an inline override on the body marker when a footer image shows.
	 * Consumed as a MINIMUM bottom clearance by the rail spacers below, never
	 * as padding: padding on the centered rail would shift the card up by half
	 * the reserve, displacing the form (the !126 regression). */
	--lx-footer-image-reserve: 0px;
	--lx-overlay-inset: 48px;
	--lx-overlay-bottom: 44px;
	--lx-band-h: 148px;
	--lx-band-h-panorama: 190px;

	/* Per-device framing (Focal Compass, EXPERIMENTAL): focal point and zoom of
	 * the one side image. Defaults reproduce the shared center-focal cover crop;
	 * extend_login_context writes inline --lx-frame-* overrides per custom device
	 * onto .lx-chrome. Applied by the media blocks at the end of this file on the
	 * shared device breakpoints (login_extender.DEVICE_BREAKPOINTS): mobile
	 * <=991, laptop 992-1439, desktop >=1440. */
	--lx-frame-desktop-pos: 50% 50%;
	--lx-frame-desktop-zoom: 1;
	--lx-frame-laptop-pos: 50% 50%;
	--lx-frame-laptop-zoom: 1;
	--lx-frame-mobile-pos: 50% 50%;
	--lx-frame-mobile-zoom: 1;
}

[data-theme="dark"] body.lx-split-active,
[data-theme-mode="dark"] body.lx-split-active {
	--lx-panel-fallback: #232323;
}

/* --------------------------------------------------------------- form rail */
/* The stock login container becomes the fixed left rail; #mfa-root (the merged
 * privileged-MFA panel, a sibling body-level section.for-login) shares the exact
 * same rail slot so the second factor sits inside the split too. #mfa-root
 * starts hidden (.hide) and is revealed by the MFA UI; :not(.hide) keeps it out
 * of the rail until then. */
body.lx-split-active .page-content-wrapper,
body.lx-split-active #mfa-root:not(.hide) {
	position: fixed;
	top: 0;
	bottom: 0;
	left: 0;
	width: var(--lx-rail-w);
	background: var(--bg-color);
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	padding: var(--lx-rail-top) var(--lx-rail-gutter) var(--lx-footer-reserve);
	overflow-y: auto;
	min-height: 0;
	z-index: 1;
}

body.lx-split-active.lx-side-left .page-content-wrapper,
body.lx-split-active.lx-side-left #mfa-root:not(.hide) {
	left: auto;
	right: 0;
}

/* Footer-image clearance WITHOUT displacing the card: matched flex spacers own
 * the rail's free space (same resting center as justify-content: center alone),
 * and only the bottom spacer refuses to shrink below the footer-image reserve.
 * With room to spare the spacers stay equal, so the card sits in its exact
 * no-footer-image position; only when the viewport is short enough that the
 * card would underlap the fixed footer image does the bottom spacer hold firm
 * and yield the card upward. Split widths only - the mobile stacked layout
 * drops the rail footer entirely (see the <=991px block below). */
@media (min-width: 992px) {
	/* When even the yielded card cannot fit, pack from the top: a centered flex
	 * overflow clips the card's top unreachably (no scroll can show it), while
	 * top-packed overflow is fully scrollable in the rail's own overflow-y. The
	 * spacers below absorb all free space, so this changes nothing while the
	 * card fits. */
	body.lx-split-active .page-content-wrapper,
	body.lx-split-active #mfa-root:not(.hide) {
		justify-content: flex-start;
	}

	body.lx-split-active .page-content-wrapper::before,
	body.lx-split-active .page-content-wrapper::after,
	body.lx-split-active #mfa-root:not(.hide)::before,
	body.lx-split-active #mfa-root:not(.hide)::after {
		content: "";
		flex: 1;
	}

	body.lx-split-active .page-content-wrapper::after,
	body.lx-split-active #mfa-root:not(.hide)::after {
		min-height: var(--lx-footer-image-reserve);
	}
}

/* The rail card sizes to the rail, not the viewport: espresso's stock website
 * chrome steps .container side padding at viewport breakpoints, which would
 * reflow the form on resize even though the rail width never changes. The rail
 * already owns the horizontal gutters, so zero the stock container padding. */
body.lx-split-active .page-content-wrapper .container,
body.lx-split-active #mfa-root .container {
	padding-left: 0;
	padding-right: 0;
}

/* Split mode: espresso renders app_logo inside .page-card-head, which would
 * duplicate the brand shown on the image (the corner chip on desktop/laptop,
 * the brand band on mobile), so the in-card logo is always hidden - one brand
 * presentation per view, at every width. */
body.lx-split-active .page-card-head img.app-logo {
	display: none;
}

/* --------------------------------------------------------------- rail footer */
/* .lx-chrome is a zero-size holder (its children are fixed); it carries the
 * inline --lx-frame-* overrides and is the single element the MFA reveal below
 * keeps visible. */
/* The footer is an opaque band the overflowing card scrolls OUT FROM UNDER
 * (same --bg-color as the rail, so the seam is invisible), and it is
 * click-transparent (pointer-events: none) so a card row that is momentarily
 * beneath it - or the MFA method menu extending into the band - still receives
 * clicks and wheel scrolling; only the footer's own links re-enable pointer
 * events below. */
body.lx-split-active .lx-footer {
	position: fixed;
	left: 0;
	bottom: 0;
	width: var(--lx-rail-w);
	padding: 0 var(--lx-rail-gutter) var(--lx-rail-gutter);
	display: flex;
	flex-direction: column;
	gap: 14px;
	z-index: 2;
	background: var(--bg-color);
	pointer-events: none;
}

body.lx-split-active.lx-side-left .lx-footer {
	left: auto;
	right: 0;
}

/* The copyright/links line: the row the footer used to be, now stacked under
 * the optional footer image above it. */
.lx-footer-meta {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: 12px;
	font-size: 11px;
	line-height: 1.4;
	font-weight: 400;
	color: var(--ink-gray-6);
}

.lx-footer-meta a {
	color: inherit;
	text-decoration: none;
	/* Re-enable clicks on the links inside the click-transparent band above. */
	pointer-events: auto;
}

.lx-footer-meta a:hover {
	text-decoration: underline;
}

.lx-footer-sep {
	opacity: 0.6;
	padding: 0 4px;
}

/* Footer image: a logo/seal/banner sized by the operator (height in px, width
 * auto so any aspect ratio is preserved) and aligned within the rail. max-width
 * keeps a very wide image inside the rail; object-fit: contain then letterboxes
 * rather than distorting if the width cap engages. */
.lx-footer-image {
	display: flex;
}

.lx-footer-image-left {
	justify-content: flex-start;
}

.lx-footer-image-center {
	justify-content: center;
}

.lx-footer-image-right {
	justify-content: flex-end;
}

.lx-footer-image img {
	width: auto;
	max-width: 100%;
	object-fit: contain;
	display: block;
}

/* --------------------------------------------------------- inline MFA (merged)
 * The MFA UI reveals #mfa-root by hiding every stock, in-flow body child
 * (including the login card wrapper AND our .lx-chrome) with an inline
 * display:none, then sets body.mfa-inline-active. The image panel and footer are
 * split chrome that must persist behind the second factor, so keep .lx-chrome
 * shown - an !important stylesheet rule overrides MFA's inline display:none
 * without touching any MFA asset. .page-content-wrapper is deliberately NOT
 * overridden, so the password card stays hidden while the factor shows. */
body.lx-split-active.mfa-inline-active .lx-chrome {
	display: block !important;
}

/* Keep the revealed #mfa-root on the rail's flex centering. Frappe's stock
 * login.js runs $(".for-login").toggle(true) on every load, which writes an
 * inline display:block onto #mfa-root (it matches .for-login); the MFA reveal
 * only removes .hide, so without this the extender's display:flex (and with it
 * the vertical centering and the ::after footer reserve) never applies and the
 * second factor renders top-packed. Scoped to .mfa-inline-active, which the
 * MFA UI removes when the panel hides, so a re-hidden panel is unaffected. */
body.lx-split-active.mfa-inline-active #mfa-root:not(.hide) {
	display: flex !important;
}

/* Pin the revealed #mfa-root into the rail. The MFA stylesheet's own inline
 * rule (`body.mfa-inline-active > #mfa-root.mfa-section { width: 100% }`) ties
 * the shared rail rule above on specificity and loads later (via body_include),
 * so it would otherwise win and stretch the factor full-width across the panel.
 * Matching `.mfa-inline-active` here raises specificity above that rule and
 * re-asserts the rail width and footer clearance; left/right come from the
 * shared rule and side-left rule, which the MFA stylesheet never contests.
 * Scoped to the split widths only - the mobile stacked block below owns the
 * <=991px layout, where the MFA panel's full width is correct. */
@media (min-width: 992px) {
	body.lx-split-active.mfa-inline-active #mfa-root:not(.hide) {
		width: var(--lx-rail-w);
		padding-bottom: var(--lx-footer-reserve);
	}
}

/* ------------------------------------------------------------- image panel */
body.lx-split-active .lx-panel {
	position: fixed;
	top: 0;
	bottom: 0;
	left: var(--lx-rail-w);
	right: 0;
	overflow: hidden;
	background: var(--lx-panel-fallback);
}

body.lx-split-active.lx-side-left .lx-panel {
	left: 0;
	right: var(--lx-rail-w);
}

.lx-panel img.lx-image {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center;
}

/* Corner brand chip (split mode): the brand's single home on the image, shown
 * in both quiet split and panorama. It sits in the top-leading corner on its
 * own top scrim, so it stays legible over any upload independently of the
 * bottom-left statement scrim, and never collides with the bottom-left overlay
 * or the top-right credit. Hidden on the mobile band (stacked block below),
 * where the brand band carries identity. Placement is side-agnostic: top-left
 * of the panel is the inner corner for a right image and the outer corner for
 * a left image, and the credit is always top-right, so the two never overlap. */
.lx-brand-scrim {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 150px;
	background: linear-gradient(
		180deg,
		rgba(var(--lx-scrim-base), 0.55),
		rgba(var(--lx-scrim-base), 0)
	);
	z-index: 2;
}

.lx-brandmark {
	position: absolute;
	top: 30px;
	left: 34px;
	z-index: 3;
	display: flex;
	align-items: center;
	gap: 11px;
	width: calc(100% - 100px);
	max-width: calc(100% - 100px);
}

.lx-brandmark img.lx-brandmark-logo {
	max-height: 30px;
	max-width: 120px;
	width: auto;
	display: block;
	flex: 0 0 auto;
}

.lx-brandmark-name {
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	font-size: 18px;
	line-height: 1.2;
	font-weight: 650;
	letter-spacing: -0.01em;
	color: var(--lx-on-image);
	text-shadow: 0 1px 10px rgba(0, 0, 0, 0.45);
}

/* Panorama scrim (P1, split mode): guarantees headline legibility on any
 * upload; never editable. */
.lx-scrim {
	position: absolute;
	inset: 0;
	background: linear-gradient(
		11deg,
		rgba(var(--lx-scrim-base), 0.78) 0%,
		rgba(var(--lx-scrim-base), 0.34) 34%,
		rgba(var(--lx-scrim-base), 0) 62%
	);
}

/* Panorama overlay (P3/P4, split mode): bottom-left of the image panel. */
.lx-overlay {
	position: absolute;
	left: var(--lx-overlay-inset);
	right: var(--lx-overlay-inset);
	bottom: var(--lx-overlay-bottom);
}

.lx-headline {
	font-size: 40px;
	line-height: 1.12;
	font-weight: 600;
	letter-spacing: -0.015em;
	color: var(--lx-on-image);
	text-wrap: balance;
	max-width: 520px;
	margin: 0;
}

.lx-welcome {
	font-size: 15px;
	line-height: 1.5;
	font-weight: 400;
	color: var(--lx-on-image-soft);
	max-width: 460px;
	margin: 10px 0 0;
}

/* Mobile band content lives in the same panel; hidden at split widths. */
.lx-band-scrim,
.lx-band-content {
	display: none;
}

/* ---------------------------------------------- image credit (attribution) */
/* Info-icon reveal, top-right of the image panel (clear of the bottom-left
 * statement overlay). The button toggles the single static credit on click,
 * tap, or keyboard activation through .is-open; hover-capable devices also
 * reveal it on hover. On-image colors are fixed (the photo is mode-neutral),
 * matching the overlay treatment above. */
.lx-credit {
	position: absolute;
	top: 20px;
	right: 20px;
	z-index: 3;
}

.lx-credit::after {
	content: "";
	position: absolute;
	top: 30px;
	right: 0;
	width: 244px;
	height: 8px;
}

.lx-credit-btn {
	width: 30px;
	height: 30px;
	padding: 0;
	border-radius: 50%;
	border: 1px solid rgba(255, 255, 255, 0.7);
	background: rgba(var(--lx-scrim-base), 0.55);
	color: var(--lx-on-image);
	font: italic 15px/1 Georgia, "Times New Roman", serif;
	display: flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
}

.lx-credit-btn:hover,
.lx-credit-btn:focus-visible {
	background: rgba(var(--lx-scrim-base), 0.82);
}

.lx-credit-pop {
	position: absolute;
	top: 38px;
	right: 0;
	width: 244px;
	background: rgba(var(--lx-scrim-base), 0.95);
	color: var(--lx-on-image);
	border-radius: 10px;
	padding: 12px 14px;
	font-size: 12.5px;
	line-height: 1.5;
	box-shadow: 0 12px 30px rgba(0, 0, 0, 0.4);
	opacity: 0;
	visibility: hidden;
	transform: translateY(-4px);
	transition: opacity 120ms ease, transform 120ms ease;
}

.lx-credit.is-open .lx-credit-pop {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
}

@media (hover: hover) {
	.lx-credit:hover .lx-credit-pop {
		opacity: 1;
		visibility: visible;
		transform: translateY(0);
	}
}

.lx-credit-title {
	font-weight: 650;
	margin-bottom: 2px;
}

.lx-credit-line {
	color: var(--lx-on-image-soft);
}

.lx-credit-link {
	color: #7fd3c4;
	text-decoration: underline;
}

.lx-credit-note {
	color: rgba(255, 255, 255, 0.6);
	font-size: 11px;
	margin-top: 6px;
}

/* ------------------------------------------- stacked mode (mobile <=991px) */
/* The image collapses to a fixed brand band pinned at the top; the form (and
 * #mfa-root in its place) flows in the normal document below it, so the mobile
 * keyboard and scroll behave naturally. Side has no meaning stacked - the band
 * is always on top - so the side-left panel offsets are reset here too.
 * 991.98px (the Bootstrap idiom this file already uses at 575.98px) pairs with
 * the (min-width: 992px) blocks above so a fractional viewport width in
 * (991, 992) - e.g. Windows 125% DPI - cannot fall between the two. */
@media (max-width: 991.98px) {
	body.lx-split-active .lx-panel,
	body.lx-split-active.lx-side-left .lx-panel {
		top: 0;
		left: 0;
		right: 0;
		bottom: auto;
		height: var(--lx-band-h);
	}

	body.lx-split-active.lx-panorama .lx-panel {
		height: var(--lx-band-h-panorama);
	}

	/* No .lx-side-left variants here: the side-left base rule only sets
	 * left/right, which position:static makes inert, and the extra class
	 * would out-specify the MFA stylesheet's own
	 * `body.mfa-inline-active > #mfa-root.mfa-section { width: 100% }`,
	 * shrink-wrapping the revealed MFA panel on a Side=Left phone. */
	body.lx-split-active .page-content-wrapper,
	body.lx-split-active #mfa-root:not(.hide) {
		position: static;
		width: auto;
		margin-top: var(--lx-band-h);
		min-height: calc(100svh - var(--lx-band-h));
		padding: 0;
		overflow-y: visible;
	}

	body.lx-split-active.lx-panorama .page-content-wrapper,
	body.lx-split-active.lx-panorama #mfa-root:not(.hide) {
		margin-top: var(--lx-band-h-panorama);
		min-height: calc(100svh - var(--lx-band-h-panorama));
	}

	/* Mobile drops the rail footer entirely. */
	body.lx-split-active .lx-footer {
		display: none;
	}

	/* The corner brand chip and the split-mode panorama layers are
	 * desktop/laptop chrome; on mobile the brand band carries identity. */
	.lx-brandmark,
	.lx-brand-scrim,
	.lx-scrim,
	.lx-overlay {
		display: none;
	}

	/* Band scrim is part of the base (it guarantees lockup legibility),
	 * not a panorama element. */
	.lx-band-scrim {
		display: block;
		position: absolute;
		inset: 0;
		background: linear-gradient(
			5deg,
			rgba(var(--lx-scrim-base), 0.62),
			rgba(var(--lx-scrim-base), 0.05) 60%
		);
	}

	.lx-band-content {
		display: block;
		position: absolute;
		left: 24px;
		right: 24px;
		bottom: 16px;
	}

	.lx-band-lockup {
		display: flex;
		align-items: center;
		gap: 9px;
	}

	.lx-band-content img.lx-band-logo {
		display: block;
		max-height: 26px;
		width: auto;
	}

	.lx-band-name {
		font-size: 14.5px;
		line-height: 1.2;
		font-weight: 650;
		color: #ffffff;
		text-shadow: 0 1px 8px rgba(0, 0, 0, 0.35);
	}

	/* Panorama band: logo above headline above welcome, so mobile always shows
	 * brand. */
	.lx-band-content.lx-band-panorama img.lx-band-logo {
		margin-bottom: 9px;
	}

	.lx-band-headline {
		font-size: 21px;
		line-height: 1.2;
		font-weight: 600;
		letter-spacing: -0.01em;
		color: #ffffff;
		margin: 0;
	}

	.lx-band-welcome {
		font-size: 12px;
		line-height: 1.45;
		font-weight: 400;
		color: var(--lx-on-image-soft);
		margin: 3px 0 0;
	}

	/* Credit info button sits top-right of the brand band; larger touch target
	 * on mobile. The band is short and .lx-panel clips overflow, so the revealed
	 * popover is positioned relative to the viewport (the band is always at the
	 * top on mobile) to avoid being cut off. */
	.lx-credit {
		top: 14px;
		right: 14px;
	}

	.lx-credit-btn {
		width: 40px;
		height: 40px;
		font-size: 18px;
	}

	.lx-credit-pop {
		position: fixed;
		top: 62px;
		right: 14px;
		z-index: 10;
	}
}

/* --------------------- per-device framing (shared breakpoints, see tokens) */
/* transform-origin at the focal point keeps the placed subject anchored while
 * zoom scales the cover-cropped image around it. */
@media (min-width: 1440px) {
	.lx-panel img.lx-image {
		object-position: var(--lx-frame-desktop-pos);
		transform: scale(var(--lx-frame-desktop-zoom));
		transform-origin: var(--lx-frame-desktop-pos);
	}
}

@media (min-width: 992px) and (max-width: 1439px) {
	.lx-panel img.lx-image {
		object-position: var(--lx-frame-laptop-pos);
		transform: scale(var(--lx-frame-laptop-zoom));
		transform-origin: var(--lx-frame-laptop-pos);
	}
}

@media (max-width: 991.98px) {
	.lx-panel img.lx-image {
		object-position: var(--lx-frame-mobile-pos);
		transform: scale(var(--lx-frame-mobile-zoom));
		transform-origin: var(--lx-frame-mobile-pos);
	}
}

/* ----------------------------------------------- sign-in motion (Direction A) */
/* Stock-card polish on the split login: focus ring and press feedback, the same
 * tokens the MFA panel uses. The credentials -> MFA hand-over and every
 * #mfa-root motion rule live in privileged_mfa.css, which serves BOTH majors;
 * this block only touches the espresso card while the split chrome is active
 * (v16-only), so the two files each declare the tokens they use - either can
 * load without the other (split without the MFA gateway; the gateway on v15
 * without the split). */
body.lx-split-active {
	--pmfa-ease-out: cubic-bezier(0.23, 1, 0.32, 1);
	--pmfa-d-press: 120ms;
	--pmfa-d-fast: 140ms;
}

body.lx-split-active .page-content-wrapper .form-control {
	transition: border-color var(--pmfa-d-fast) ease, box-shadow var(--pmfa-d-fast) ease;
}

body.lx-split-active .page-content-wrapper .form-control:focus {
	border-color: var(--gray-900, #171717);
	box-shadow: 0 0 0 3px rgba(23, 23, 23, 0.08);
}

body.lx-split-active .page-content-wrapper .btn-login {
	transition: transform var(--pmfa-d-press) var(--pmfa-ease-out),
		background-color var(--pmfa-d-fast) ease;
}

body.lx-split-active .page-content-wrapper .btn-login:active {
	transform: scale(0.97);
}

@media (prefers-reduced-motion: reduce) {
	body.lx-split-active .page-content-wrapper .btn-login:active {
		transform: none;
	}
}

/* Espresso-xs (<576px): the stock card goes full-bleed with its own 100svh
 * minimum; below the band it should fill the remaining form area instead. */
@media (max-width: 575.98px) {
	body.lx-split-active .page-card,
	body.lx-split-active #mfa-root .page-card {
		min-height: calc(100svh - var(--lx-band-h));
	}

	body.lx-split-active.lx-panorama .page-card,
	body.lx-split-active.lx-panorama #mfa-root .page-card {
		min-height: calc(100svh - var(--lx-band-h-panorama));
	}
}
