/*
 * ============================================================
 * FILE    : signin.css
 * PURPOSE : Styles for the eC-Portal sign-in page.
 *
 * TABLE OF CONTENTS
 *   1.  CSS RESET & BOX-SIZING
 *   2.  CSS CUSTOM PROPERTIES (DESIGN TOKENS)
 *   3.  BASE HTML / BODY
 *   4.  CUSTOM FONT FACE (@font-face Roboto)
 *   5.  BACKGROUND LAYER  (.page-background)
 *   6.  STAGE — full-viewport centering wrapper  (.viewport-stage)
 *   7.  MAIN CARD — frosted-glass two-column card  (.login-card)
 *       7a. Card entrance animation  (@keyframes slideUpFadeIn)
 *   8.  LEFT PANEL — green decorative panel  (.decorative-left-panel)
 *       8a. Decorative overlay pseudo-element  (.decorative-left-panel::before)
 *       8b. Image stack  (.image-stack-container, .globe-image-layer, .rotating-dot-overlay)
 *       8c. Rotating dot-pattern animation  (@keyframes rotateClockwise)
 *       8d. PCB image  (.product-image-wrapper, .product-image)
 *   9.  RIGHT PANEL — form panel  (.form-right-panel)
 *       9a. Decorative dot-grid overlay  (.form-right-panel::before)
 *       9b. Form wrapper  (.form-content-wrapper)
 *  10.  BRAND BADGE  (.brand-identity-badge, .app-name-label, etc.)
 *  11.  FORM TYPOGRAPHY  (.form-title-heading, .form-subtitle-text)
 *  12.  INPUT FIELDS  (.form-field-group, .input-label-text, .input-icon-wrapper,
 *                      .input-left-icon, .text-input-field, .password-toggle-button)
 *  13.  SIGN-IN BUTTON  (.submit-signin-button, .button-arrow-icon, .button-loading-spinner)
 *       13a. Spinner animation  (@keyframes rotateSpinner)
 *  14.  ALERT / ERROR MESSAGES  (.inline-error-alert)
 *  15.  RESET-PASSWORD MODAL  (.modal-backdrop-overlay, .modal-dialog-card,
 *                              .modal-header-bar, .modal-scrollable-body, .modal-action-footer)
 *  16.  PASSWORD REQUIREMENTS CHECKLIST  (.password-requirements-box, .requirement-met, .requirement-unmet)
 *  17.  FOOTER  (.page-form-footer, .copyright-text)
 *  18.  UTILITY / HELPER CLASSES
 *  19.  PAGE LOADING OVERLAY  (#loading-image)
 *  20.  GLOBAL ELEMENT RESETS (headings, lists, anchors, images, etc.)
 *  21.  RESPONSIVE BREAKPOINTS (Mobile)
 * ============================================================
 */


/* ============================================================
   1. CSS RESET & BOX-SIZING

   WHY THIS EXISTS:
   Different browsers have different default styles (margins, paddings,
   border behaviours). Without a reset, your layout can look different
   in Chrome vs Firefox vs Safari. This block neutralises those
   browser differences so every developer starts from the same baseline.

   box-sizing: border-box
   ─────────────────────
   By default, CSS uses box-sizing: content-box, meaning:
     declared width = content only
     actual rendered width = declared width + padding + border

   With border-box:
     declared width = content + padding + border
     actual rendered width = exactly what you declared

   This makes width calculations predictable (no more adding up padding
   and border values in your head).

   The *::before and *::after selectors apply the same rule to CSS
   pseudo-elements, which are commonly used for decorative shapes and
   overlays throughout this file.

   margin: 0 and padding: 0
   ─────────────────────────
   Browsers add default margins to elements like <h1>, <p>, <ul>, etc.
   Zeroing them out here means our custom spacing rules are the only
   ones that apply — no surprise gaps from browser defaults.
   ============================================================ */
*,
*::before,
*::after {
	box-sizing: border-box;
	margin: 0;
	padding: 0;
}


/* ============================================================
   2. CSS CUSTOM PROPERTIES (DESIGN TOKENS)

   WHY CUSTOM PROPERTIES (CSS VARIABLES)?
   Custom properties let you define a value once on :root and reuse it
   everywhere. If the brand green changes from #2a9f00 to something else,
   you update one line here instead of hunting down every occurrence in
   the file. This is especially important in a team where the design
   system can evolve over time.

   :root is the highest-level element in the DOM (equivalent to <html>),
   so variables defined here are accessible to every element on the page
   via var(--variable-name).

   ── Colour Palette ──────────────────────────────────────────────────
   --brand-primary-green
       The main brand green used on buttons, icons, focus states, and
       active elements. All interactive affordances use this colour so
       users quickly learn "green = actionable".

   --brand-gradient-start-green
       A slightly lighter green used as the starting colour of the
       button gradient (gradient goes from this → --brand-primary-green).
       Two-stop gradients look more polished than flat colour.

   --brand-deep-green
       Kept as a semantic alias of --brand-primary-green. Some components
       (e.g. the panel background) use this name so it is clear they
       represent "deep" brand colour, not an accent.

   --brand-pale-green-tint
       A very light green tint (#e8f7e4) used as a background for the
       brand badge and hover fill states. Provides brand-consistent
       colour without overwhelming the white form panel.

   ── Text Colours ────────────────────────────────────────────────────
   --text-color-dark
       Near-black dark green for headings, labels, and primary text.
       Using a dark green instead of pure black keeps the text on-brand
       while maintaining high contrast for accessibility.

   --text-color-medium
       Medium green for secondary text like subtitles, helper text, and
       non-critical labels. Sits between dark and light for hierarchy.

   --text-color-muted
       Muted, desaturated green for the least important text (placeholders,
       footnotes). Keeps contrast accessible while visually de-emphasising.

   ── Shape ───────────────────────────────────────────────────────────
   --default-border-radius
       12px applied consistently to inputs, buttons, and smaller containers.
       Using a single variable ensures all interactive elements share the
       same corner rounding, creating visual cohesion.
   ============================================================ */
:root {
	/* Brand greens — primary interactive colour and its tonal variants */
	--brand-primary-green:        #2a9f00;
	--brand-gradient-start-green: #369926;
	--brand-deep-green:           #2a9f00;
	--brand-pale-green-tint:      #e8f7e4;

	/* Text hierarchy — dark → medium → muted for visual weight control */
	--text-color-dark:   #1a2e14;
	--text-color-medium: #4a6741;
	--text-color-muted:  #7a9b75;

	/* Consistent corner rounding for inputs, buttons, and small containers */
	--default-border-radius: 12px;
}


/* ============================================================
   3. BASE HTML / BODY

   WHY height: 100%?
   By default, <html> and <body> only grow as tall as their content.
   Setting height: 100% makes both take up the full viewport height,
   which is needed so the flex container (.viewport-stage) can centre
   the login card vertically using align-items: center.

   WHY overflow: hidden?
   The decorative animated elements (rotating dot pattern, frosted card)
   can trigger scroll on some browsers when they extend slightly outside
   the viewport. overflow: hidden prevents a scrollbar from appearing
   on a page that is intentionally scroll-free.

   WHY font-family on both html/body AND body alone?
   The html/body block sets the base font. The second body rule with
   !important is a defensive override for Bootstrap's `font-family`
   declaration, which sometimes wins the cascade without !important.
   This ensures Roboto is always applied regardless of load order.
   ============================================================ */
html,
body {
	height: 100%;
	font-family: 'Roboto', sans-serif;
	/* Sign-in page has no scrollable content — lock overflow to prevent
	   animated elements from causing an unexpected scrollbar */
	overflow: hidden;
}

/* !important overrides Bootstrap's body font-family reset */
body {
	font-family: "Roboto" !important;
}


/* ============================================================
   4. CUSTOM FONT FACE

   WHY @font-face?
   Roboto is self-hosted here rather than loaded from Google Fonts.
   Self-hosting avoids third-party network requests (privacy, speed),
   removes the dependency on an external CDN, and ensures the font
   loads even in network-restricted environments (e.g. an internal
   company portal behind a firewall).

   The .woff format is supported by all modern browsers and has a
   good compression ratio. If you need to support very old browsers,
   a .woff2 (better compression) / .woff (fallback) pair is ideal.

   The path is relative to the CSS file's location on the server.
   If you move this CSS file, update the src path accordingly.
   ============================================================ */
@font-face {
	font-family: 'Roboto';
	src: url('../../accounts/fonts/Roboto-Regular-webfont.woff');
	font-weight: normal;
	font-style: normal;
}


/* ============================================================
   5. BACKGROUND LAYER  (.page-background)

   This <div> sits directly inside <body> and covers the entire
   viewport with a world-map image. It is purely decorative.

   WHY position: fixed instead of absolute or static?
   position: fixed pins the element relative to the viewport, not the
   page document. Even though scrolling is disabled on this page, using
   fixed guarantees the background never shifts if content somehow
   causes the document to be taller than the viewport.

   inset: 0
   A shorthand for top: 0; right: 0; bottom: 0; left: 0.
   Together with position: fixed, this stretches the element to cover
   every edge of the viewport.

   z-index: 0
   Stacks the background behind everything else. The .viewport-stage
   wrapper uses z-index: 10, so it renders on top of this layer.

   background: url(...) no-repeat center center / cover
   ─ no-repeat: draw the image once, no tiling
   ─ center center: position the image at the exact middle of the element
   ─ / cover: scale the image (maintaining aspect ratio) so it fills
              the element completely, even if some edges are cropped
   ============================================================ */
.page-background {
	position: fixed;
	inset: 0;
	z-index: 0;
	background: url("../../../static/base/images/world-map.webp") no-repeat center center / cover;
}


/* ============================================================
   6. STAGE / VIEWPORT WRAPPER  (.viewport-stage)

   A full-height flex container whose sole job is to centre the
   .login-card both horizontally and vertically inside the viewport.

   WHY position: relative and z-index: 10?
   The background layer (.page-background) has z-index: 0.
   Without a z-index on this element, stacking context is ambiguous
   and the card may render behind the background on some browsers.
   z-index: 10 guarantees the card and all its children are painted
   on top of the background image.

   height: 100vh
   Ensures the stage always spans the full visible window height,
   regardless of the <body> height calculation.

   padding: 24px
   Provides breathing room on small screens so the login card never
   touches the edge of the viewport. The card itself uses max-width,
   so on large screens the padding has no visible effect.
   ============================================================ */
.viewport-stage {
	position: relative;
	z-index: 10;
	height: 100vh;
	display: flex;
	align-items: center;      /* centres the card vertically */
	justify-content: center;  /* centres the card horizontally */
	padding: 24px;            /* safe gap so the card never touches screen edges */
}


/* ============================================================
   7. MAIN LOGIN CARD  (.login-card)

   The two-column frosted-glass card that is the centrepiece of
   the sign-in page. It holds .decorative-left-panel (55%) on the
   left and .form-right-panel (45%) on the right.

   ── Layout ──────────────────────────────────────────────────
   display: flex places the two panels side by side as flex children.
   max-width: 980px caps the card width on large monitors so text
   lines don't become uncomfortably long.
   min-height: 560px prevents the card from collapsing to a tiny
   height when form content is minimal (e.g. OTP step with one field).

   ── Frosted-Glass Visual Effect ─────────────────────────────
   backdrop-filter: blur(28px) saturate(1.8)
   This is the CSS property that creates the "frosted glass" look.
   It applies a blur and colour saturation boost to whatever is visible
   *behind* the element (the world-map background in this case).
   The result is a translucent card that softly shows the map beneath.

   -webkit-backdrop-filter is the same property with the Safari/older
   Chrome vendor prefix. Always include both for cross-browser support.

   background: rgba(255, 255, 255, 0.72)
   A semi-transparent white background. The 0.72 opacity lets the
   blurred world-map show through while keeping form text readable.

   ── Border & Shadow ─────────────────────────────────────────
   border: 1px solid rgba(76, 174, 53, 0.18)
   A barely-visible green tint border that ties the card to the brand
   colour without making the border look heavy.

   box-shadow uses three layers:
     1. A tight, small shadow (4px) — simulates a close light source,
        gives the card a subtle "lifted off the page" feel.
     2. A green-tinted medium shadow (48px) — the main soft glow that
        makes the card feel luminous on the world-map background.
     3. A large dark outer shadow (90px) — creates depth so the card
        looks like it is floating above the page.
   The inset shadow adds a bright inner highlight along the top edge,
   which is a common trick to simulate a light source above the card.

   ── Entrance Animation ──────────────────────────────────────
   The card begins invisible (opacity: 0) and slightly below and
   smaller than its final position (translateY + scale). The
   slideUpFadeIn animation (defined below) brings it to its final
   state 0.15s after the page loads.

   animation-fill-mode: forwards
   Keeps the final animation state (opacity: 1, no transform) after
   the animation finishes. Without "forwards", the card would snap
   back to opacity: 0 when the animation ends.
   ============================================================ */
.login-card {
	width: 100%;
	max-width: 980px;
	min-height: 560px;
	display: flex;
	background: rgba(255, 255, 255, 0.72);
	border: 1px solid rgba(76, 174, 53, 0.18);
	border-radius: 24px;
	box-shadow:
		0 4px 6px rgba(0, 0, 0, 0.04),          /* tight ambient shadow — lifted feel */
		0 16px 48px rgba(76, 174, 53, 0.10),     /* green-tinted glow — brand connection */
		0 40px 90px rgba(0, 0, 0, 0.09),         /* large dark outer shadow — depth */
		inset 0 1px 0 rgba(255, 255, 255, 0.95); /* inner top highlight — simulated light */
	backdrop-filter: blur(28px) saturate(1.8);
	-webkit-backdrop-filter: blur(28px) saturate(1.8);
	overflow: hidden;

	/* Initial hidden state — animation will reveal it */
	opacity: 0;
	transform: translateY(18px) scale(0.985);

	/* 0.15s delay lets the page background render first, then the card appears */
	animation: slideUpFadeIn 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.15s forwards;
}

/*
 * 7a. Card entrance animation keyframe
 *
 * cubic-bezier(0.22, 1, 0.36, 1) is a "spring-like" easing curve.
 * It starts fast then decelerates sharply at the end, mimicking the
 * natural feel of something sliding into place and settling.
 * The "to" block defines the final resting state of the card.
 */
@keyframes slideUpFadeIn {
	to {
		opacity: 1;
		transform: translateY(0) scale(1);
	}
}


/* ============================================================
   8. LEFT DECORATIVE PANEL  (.decorative-left-panel)

   The green panel on the left side of the login card. It is purely
   decorative — it contains the animated globe/dot imagery and the
   product image but no form inputs.

   WHY width: 55%?
   Giving the decorative side more space than the form side (55/45)
   makes the card feel spacious. The form content on the right
   naturally fits in 45% without feeling cramped.

   border-radius: 24px 0 0 24px
   Only the left two corners are rounded to match the outer card radius.
   The right edge is square because it is flush against the form panel.

   overflow: hidden
   The animated .rotating-dot-overlay extends slightly beyond the
   .image-stack-container with inset: -20px. overflow: hidden clips
   those edges so the animation never bleeds outside the green panel.

   position: relative
   Required so that the ::before pseudo-element (the gradient overlay)
   can be positioned absolutely relative to this panel.
   ============================================================ */
.decorative-left-panel {
	width: 55%;
	background: linear-gradient(145deg, #2a9f00 0%, #2a9f00 40%, #2a9f00 100%);
	border-radius: 24px 0 0 24px;
	position: relative;
	overflow: hidden;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	padding: 44px 40px;
}

/*
 * 8a. Gradient depth overlay on the left panel
 *
 * Two radial gradients layered via background-image create a subtle
 * lighting effect on the flat green background:
 *   - Top-left light spot: simulates a light source in the upper corner
 *   - Bottom-right dark spot: simulates shadow falling away from the light
 *
 * Together they give the panel a gentle three-dimensional quality.
 *
 * position: absolute + inset: 0 makes the overlay fill the entire panel.
 * pointer-events: none is critical — without it, this invisible overlay
 * would block all mouse and touch events on the carousel/images below it.
 */
.decorative-left-panel::before {
	content: '';
	position: absolute;
	inset: 0;
	background-image:
		radial-gradient(circle at 20% 20%, rgba(255, 255, 255, 0.08) 0%, transparent 50%),
		radial-gradient(circle at 80% 80%, rgba(0, 0, 0, 0.08) 0%, transparent 50%);
	pointer-events: none;
}

/*
 * 8b. Image stack container (.image-stack-container)
 *
 * A square container that acts as a positioning context for the two
 * images layered inside it:
 *   .globe-image-layer    — the world-map globe background image
 *   .rotating-dot-overlay — the animated dot pattern that spins on top
 *
 * display: flex + align-items/justify-content: center ensures the
 * product image wrapper (.product-image-wrapper) inside is centred.
 *
 * flex-shrink: 0 prevents this container from shrinking when the
 * panel is narrower than 320px (useful on tablet sizes).
 */
.image-stack-container {
	position: relative;
	width: 320px;
	height: 320px;
	display: flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
}

/*
 * Globe background image layer
 *
 * Fills the entire stack container via inset: 0 (position: absolute).
 * background-size: contain scales the globe image down to fit inside
 * the container without cropping, maintaining its aspect ratio.
 * opacity: 0.55 makes it translucent so the green panel shows through —
 * the globe is a subtle texture, not the focal point.
 */
.globe-image-layer {
	position: absolute;
	inset: 0;
	background: url("../../../static/base/images/globe-map.webp") no-repeat center/contain;
	opacity: 0.55;
}

/*
 * Rotating dot-pattern overlay
 *
 * Sits on top of the globe image and spins continuously.
 * inset: -20px extends the element 20px beyond all four edges of the
 * parent container. This prevents blank corners from appearing during
 * rotation — the pattern remains fully filled even at diagonal angles.
 *
 * opacity: 0.30 keeps the dots very subtle so they don't compete with
 * the product image rendered above them.
 *
 * The rotateClockwise animation (defined below) handles the spinning.
 */
.rotating-dot-overlay {
	position: absolute;
	inset: -20px;
	background: url("../../../static/base/images/dot-pattern.webp") no-repeat center/contain;
	opacity: 0.30;
	animation: rotateClockwise 28s linear infinite;
}

/*
 * 8c. Clockwise rotation animation
 *
 * Rotates from 0° to 360° over 28 seconds in an even linear pace.
 * "infinite" means it loops forever as long as the page is open.
 * 28 seconds is slow enough to be calming rather than distracting.
 */
@keyframes rotateClockwise {
	from { transform: rotate(0deg); }
	to   { transform: rotate(360deg); }
}

/*
 * 8d. Product image wrapper and image
 *
 * The product PCB image is centred inside the image stack and sits
 * above the globe and dot layers (z-index: 3).
 *
 * perspective: 900px enables CSS 3D transforms on child elements.
 * Without perspective, 3D rotation transforms look flat and unrealistic.
 * The value controls how strong the 3D effect appears — 900px gives
 * a subtle, natural-looking depth.
 *
 * top: 25px and left: 22px shift the image slightly off-centre,
 * which creates a more dynamic and less static composition.
 */
.product-image-wrapper {
	position: relative;
	z-index: 3;
	width: 240px;
	height: 240px;
	perspective: 900px;
	top: 25px;
	left: 22px;
}

.product-image {
	width: 80%;
	height: 80%;
	background: url("../../../static/base/images/pcb-e-white.webp") no-repeat center/contain;
	border-radius: 20px;
}


/* ============================================================
   9. RIGHT FORM PANEL  (.form-right-panel)

   The white panel on the right side of the card that holds all
   form content: the brand badge, heading, inputs, and button.

   WHY width: 45% and justify-content: flex-start?
   The form content naturally flows top-to-bottom. flex-start ensures
   the brand badge, heading, and inputs stack from the top rather than
   being distributed evenly (which would space them awkwardly).

   padding: 64px 48px
   Generous top/bottom padding gives the form visual breathing room.
   64px top ensures the brand badge doesn't sit too close to the card edge.

   position: relative
   Required as a positioning context for the ::before dot-grid overlay.
   ============================================================ */
.form-right-panel {
	width: 45%;
	display: flex;
	flex-direction: column;
	justify-content: flex-start;
	padding: 38px 48px;
	position: relative;
}

/*
 * 9a. Dot-grid texture overlay for the right panel
 *
 * A very faint repeating dot pattern gives the white form panel
 * a subtle texture, preventing it from looking completely flat.
 *
 * How the dots are made:
 * radial-gradient(circle, rgba(76, 174, 53, 0.18) 1px, transparent 1px)
 *   → Draws a 1px green dot at the centre of each tile
 * background-size: 22px 22px
 *   → Each tile is 22×22px, creating an evenly-spaced grid of dots
 *
 * opacity: 0.45 makes the dots very faint — they should be almost
 * invisible and serve only as a subtle texture hint.
 *
 * border-radius: 0 0 24px 24px clips the dots to the card's right
 * rounded corners (bottom-right and top-right of the card).
 *
 * pointer-events: none is essential here — the overlay must not
 * intercept click/tap events destined for the form inputs below it.
 */
.form-right-panel::before {
	content: '';
	position: absolute;
	inset: 0;
	background-image: radial-gradient(circle, rgba(76, 174, 53, 0.18) 1px, transparent 1px);
	background-size: 22px 22px;
	opacity: 0.45;
	pointer-events: none;
	border-radius: 0 24px 24px 0;
}

/*
 * 9b. Inner form content wrapper (.form-content-wrapper)
 *
 * WHY z-index: 2?
 * The dot-grid pseudo-element (::before) is in the same stacking
 * context as this wrapper. Without z-index: 2, the dots could paint
 * on top of the form content in some browsers.
 *
 * WHY display: flex + flex-direction: column + flex: 1?
 * This makes the wrapper stretch to fill the entire panel height
 * (flex: 1 on a flex child means "take all remaining space").
 * The footer inside uses margin-top: auto to push itself to the
 * bottom of this flex column, creating a footer that sticks to
 * the bottom of the panel regardless of how much form content there is.
 */
.form-content-wrapper {
	position: relative;
	z-index: 2;
	display: flex;
	flex-direction: column;
	flex: 1;
}


/* ============================================================
   10. BRAND IDENTITY BADGE  (.brand-identity-badge)

   A pill-shaped container at the top of the form panel that displays
   the eC-Portal logo and the application name side by side.

   WHY border-radius: 99px?
   Any value larger than half the element's height creates a fully
   rounded "pill" shape. 99px is used instead of 50% because 50%
   on a non-square element creates an ellipse, not a pill.

   gap: 15px spaces the logo image and text label apart without
   needing margins on either child element.

   margin-bottom: 36px separates the badge from the form heading below,
   giving both elements visual breathing room.
   ============================================================ */
.brand-identity-badge {
	display: flex;
	align-items: center;
	gap: 15px;
	justify-content: center;
	background: var(--brand-pale-green-tint);
	border: 1px solid rgba(76, 174, 53, 0.25);
	border-radius: 99px;
	padding: 10px 15px;
	margin-bottom: 36px;
}

/*
 * Remove any default image border that Bootstrap might apply.
 * Bootstrap older versions add a border to images by default.
 */
.brand-identity-badge img {
	border: none;
}

/*
 * App name label text displayed next to the logo inside the badge.
 * letter-spacing: 0.10em adds extra space between characters,
 * giving it a premium, title-like appearance.
 */
.app-name-label {
	font-size: 1.72rem;
	font-weight: 700;
	letter-spacing: 0.10em;
	color: var(--brand-primary-green);
}

/*
 * Cap the logo image at 25px tall so it stays proportional inside
 * the badge regardless of the image's original dimensions.
 */
.brand-identity-badge img {
	height: 25px;
}


/* ============================================================
   11. FORM TYPOGRAPHY

   .form-title-heading
   The main heading on each form step (e.g. "Welcome Back", "Enter OTP").
   2.25rem is large enough to establish clear visual hierarchy without
   overwhelming the relatively narrow 45% panel.
   line-height: 1.2 keeps multi-line headings tight and readable.

   .form-subtitle-text
   Secondary text below the heading that gives context
   (e.g. "Sign in to continue to eC-Portal").
   margin-bottom: 32px provides a gap between the subtitle and
   the first input field below it.
   ============================================================ */
.form-title-heading {
	font-family: 'Roboto', sans-serif;
	font-size: 2.25rem;
	font-weight: 700;
	color: var(--text-color-dark);
	line-height: 1.2;
	margin-bottom: 6px;
}

.form-subtitle-text {
	font-size: 1.35rem;
	color: var(--text-color-medium);
	margin-bottom: 32px;
	font-weight: 400;
}


/* ============================================================
   12. INPUT FIELDS

   Structure for each field group:
   ┌─ .form-field-group ──────────────────────────────────────┐
   │  <label class="input-label-text">Username</label>        │
   │  ┌─ .input-icon-wrapper ─────────────────────────────┐   │
   │  │  [icon]  <input class="text-input-field" />  [👁] │   │
   │  └───────────────────────────────────────────────────┘   │
   └──────────────────────────────────────────────────────────┘

   .form-field-group    — spacing wrapper for one label + input group
   .input-label-text    — <label> element above the input
   .input-icon-wrapper  — position:relative container; anchors icon + toggle
   .input-left-icon     — decorative SVG icon on the left inside the input
   .text-input-field    — the actual <input> element
   .password-toggle-button — eye icon button to show/hide password
   ============================================================ */

/*
 * Vertical spacing between consecutive field groups.
 * 18px provides a comfortable gap that groups label+input together
 * but separates them clearly from the next field group.
 */
.form-field-group {
	margin-bottom: 18px;
}

/*
 * Bold label above each input field.
 * display: block ensures the label sits on its own line above the input.
 * letter-spacing: 0.03em adds very slight character spacing for legibility.
 * font-weight: 700 !important overrides Bootstrap's default label style
 * which sets font-weight: 100 (see section 20).
 */
.input-label-text {
	display: block;
	font-size: 1.3rem;
	font-weight: 700 !important;
	color: var(--text-color-dark);
	margin-bottom: 7px;
	letter-spacing: 0.03em;
}

/*
 * position: relative turns this wrapper into a positioning context
 * so that .input-left-icon and .password-toggle-button can be positioned
 * absolutely inside it (relative to this wrapper, not the page).
 */
.input-icon-wrapper {
	position: relative;
}

/*
 * Left-side icon inside the input (person icon for username,
 * lock icon for password).
 *
 * position: absolute + left: 13px places it 13px from the left edge.
 * top: 40% + transform: translateY(-50%) centres it slightly above
 * the mathematical midpoint — inputs with labels look better when
 * icons are at 40% rather than 50%.
 *
 * pointer-events: none is critical — without it, the icon would
 * intercept clicks meant for the input below it, making the input
 * harder to focus.
 *
 * transition: color 0.2s enables a smooth colour change when the
 * :focus-within state activates (see rule below).
 */
.input-left-icon {
	position: absolute;
	left: 13px;
	top: 40%;
	transform: translateY(-50%);
	color: #aac8a6;
	pointer-events: none;
	display: flex;
	transition: color 0.2s;
}

/*
 * When any focusable descendant of .input-icon-wrapper receives focus
 * (i.e. when the user clicks into the input), turn the left icon green.
 * :focus-within matches the parent when any child is focused.
 * This provides a visual cue that the field is active.
 */
.input-icon-wrapper:focus-within .input-left-icon {
	color: var(--brand-primary-green);
}

/*
 * The actual <input> element.
 *
 * padding-left: 41px reserves space for the left icon:
 *   13px (icon's left offset) + ~16px (icon width) + 12px (gap) = 41px
 * Without this, the icon would overlap the typed text.
 *
 * -webkit-appearance: none removes the default iOS/Safari input styling
 * (rounded corners, inner shadow) that can make inputs look inconsistent.
 *
 * The transition on border-color, box-shadow, and background creates
 * smooth visual feedback when the field gains and loses focus.
 */
.text-input-field {
	width: 100%;
	background: rgba(255, 255, 255, 0.85);
	border: 1.5px solid rgba(76, 174, 53, 0.20);
	border-radius: var(--default-border-radius);
	padding: 11.5px 14px 11.5px 41px;
	font-family: 'Roboto', sans-serif;
	font-size: 1.25rem;
	color: var(--text-color-dark) !important;
	outline: none;
	transition: border-color 0.2s, box-shadow 0.2s, background 0.2s;
	-webkit-appearance: none;
}

/*
 * Inside the reset-password modal, input icons are not used,
 * so the large left padding is not needed. Override it to the
 * standard padding so text starts at the natural position.
 */
.modal-scrollable-body .text-input-field {
	padding-left: 16px !important;
}

/*
 * Placeholder text colour.
 * #b8d4b4 is a pale, desaturated green — visible enough to show hint
 * text but clearly distinguished from real typed text.
 */
.text-input-field::placeholder {
	color: #b8d4b4;
}

/*
 * Focus state visual feedback:
 *   border-color: green  — clearly shows which field is active
 *   box-shadow           — a 3px green ring around the input (not inside it)
 *                          The ring is separate from the border so it
 *                          doesn't change the layout dimensions.
 *   background: #fff     — fully opaque white; slightly more "activated"
 *                          than the default 85% opacity background.
 */
.text-input-field:focus {
	border-color: var(--brand-primary-green);
	box-shadow: 0 0 0 3px rgba(76, 174, 53, 0.13);
	background: #fff;
}

/*
 * When the password field has a visibility toggle button (.has-toggle),
 * add extra right padding so typed text doesn't slide under the button.
 * 46px = button width (28px) + right offset (12px) + gap (6px).
 */
.text-input-field.has-toggle {
	padding-right: 46px;
}

/*
 * Password visibility toggle button (the eye icon).
 * Positioned on the right side inside the input wrapper.
 *
 * transparent background and no border make it look like a pure icon
 * rather than a traditional button — consistent with modern form UX.
 *
 * transition: color 0.2s ensures the colour change on hover/focus
 * is smooth rather than instant.
 */
.password-toggle-button {
	position: absolute;
	right: 12px;
	top: 40%;
	transform: translateY(-50%);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 28px;
	height: 28px;
	border: none;
	background: transparent;
	color: #8fb08a;
	cursor: pointer;
	padding: 0;
	transition: color 0.2s;
	outline: none;
}

/*
 * Bootstrap sometimes adds decorative ::before and ::after content
 * to buttons (e.g. from .btn styles). These can create unwanted
 * visual artefacts on the icon-only toggle button. Force them hidden.
 */
.password-toggle-button::before,
.password-toggle-button::after {
	display: none !important;
}

/* Change the icon to full brand green on hover/focus as a clear interactive cue */
.password-toggle-button:hover,
.password-toggle-button:focus {
	color: var(--brand-primary-green);
	outline: none;
}

.password-toggle-button svg {
	width: 18px;
	height: 18px;
}

/*
 * ── Password toggle icon switching logic ─────────────────────────────────
 *
 * Two SVG icons live inside .password-toggle-button:
 *   .icon-eye       — standard eye icon (shown when password is HIDDEN)
 *   .icon-eye-off   — crossed-out eye icon (shown when password is VISIBLE)
 *
 * Default state (password hidden):
 *   .icon-eye → visible (display: block via flex inheritance)
 *   .icon-eye-off → hidden (display: none)
 *
 * When JS toggles password visibility, it adds class "is-visible" to the
 * button, which swaps which icon is shown. This is cleaner than
 * JavaScript directly manipulating SVG innerHTML.
 *
 * Legacy Font Awesome classes (.fa-eye, .fa-eye-slash) are also handled
 * for compatibility with older parts of the codebase that may still use them.
 * ─────────────────────────────────────────────────────────────────────── */

/* Default: hide the "eye crossed out" icon (password is hidden = show eye icon) */
.password-toggle-button .icon-eye-off {
	display: none;
}

/* Font Awesome legacy: .fa-eye class = "password is currently VISIBLE" */
.password-toggle-button.fa-eye .icon-eye     { display: none; }
.password-toggle-button.fa-eye .icon-eye-off { display: block; }

/* Font Awesome legacy: .fa-eye-slash class = "password is currently HIDDEN" */
.password-toggle-button.fa-eye-slash .icon-eye     { display: block; }
.password-toggle-button.fa-eye-slash .icon-eye-off { display: none; }

/* Modern approach: .is-visible class added by JS = "password is currently VISIBLE" */
.password-toggle-button.is-visible .icon-eye     { display: none; }
.password-toggle-button.is-visible .icon-eye-off { display: block; }


/* ============================================================
   13. SIGN-IN / SUBMIT BUTTON  (.submit-signin-button)

   Used across multiple form steps:
     - "Sign In" on the main login form
     - "Validate" on the OTP/TOTP verification forms
     - "Save Password" inside the reset-password modal

   WHY a gradient instead of a flat colour?
   Linear gradients on buttons give a subtle sense of volume and depth,
   making the button look slightly three-dimensional without any shadow
   tricks. It also prevents the button from looking completely flat on
   high-contrast screens.

   The gradient goes from --brand-gradient-start-green (slightly lighter)
   at 135° (top-left) to --brand-primary-green (deeper) at bottom-right.
   This direction follows the natural top-left light source convention.

   letter-spacing: 0.04em adds slight spacing to the button label text
   for a more prominent, "call to action" feel.
   ============================================================ */
.submit-signin-button {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	width: 100%;
	margin-top: 10px;
	padding: 13px;
	background: linear-gradient(135deg, var(--brand-gradient-start-green) 0%, var(--brand-primary-green) 100%);
	border: none;
	border-radius: var(--default-border-radius);
	color: #fff;
	font-family: 'Roboto', sans-serif;
	font-size: 1.5rem;
	font-weight: 700;
	letter-spacing: 0.04em;
	cursor: pointer;
	transition: opacity 0.2s, box-shadow 0.2s, transform 0.15s;
	box-shadow:
		0 4px 16px rgba(76, 174, 53, 0.35),  /* green glow — brand-connected shadow */
		0 1px 3px rgba(76, 174, 53, 0.2);    /* tight base shadow — grounding effect */
}

/*
 * Hover: lift the button 1px upward and deepen the green glow.
 * translateY(-1px) creates the "press to activate" visual cue.
 * The deeper shadow at 24px spread reinforces the lifted appearance.
 */
.submit-signin-button:hover {
	box-shadow: 0 6px 24px rgba(76, 174, 53, 0.45);
	transform: translateY(-1px);
}

/*
 * Active (button is being pressed): return to the resting position
 * so the button appears to "press in" when clicked.
 */
.submit-signin-button:active {
	transform: translateY(0);
}

/*
 * Disabled state (while a network request is pending):
 * opacity: 0.65 visually communicates that the button is unavailable.
 * cursor: not-allowed gives the user a clear "can't click" signal.
 * transform: none prevents the hover lift from applying while disabled.
 */
.submit-signin-button:disabled {
	opacity: 0.65;
	cursor: not-allowed;
	transform: none;
}

/*
 * Arrow icon inside the button.
 * On hover, the arrow nudges 3px to the right — a small motion cue
 * that reinforces "click here to proceed forward".
 */
.button-arrow-icon {
	transition: transform 0.2s;
}

.submit-signin-button:hover .button-arrow-icon {
	transform: translateX(3px);
}

/*
 * 13a. Loading spinner inside the submit button
 *
 * Hidden by default (display: none). JavaScript shows it by setting
 * display: inline-block while waiting for the server's authentication
 * response (/authcheck/ endpoint).
 *
 * HOW THE SPINNER WORKS:
 * It's a 16×16px circle (border-radius: 50%) with a border.
 * Most of the border is semi-transparent white (the "track").
 * Only border-top-color is fully opaque white (the "arc").
 * As the element rotates (rotateSpinner animation), the opaque arc
 * appears to chase itself around the circle — a classic CSS spinner.
 *
 * 0.7s completes one rotation in 700ms — fast enough to show activity
 * but not so fast it feels frantic.
 */
.button-loading-spinner {
	display: none;
	width: 16px;
	height: 16px;
	border: 2px solid rgba(255, 255, 255, 0.3);  /* faint circular track */
	border-top-color: #fff;                        /* bright moving arc */
	border-radius: 50%;
	animation: rotateSpinner 0.7s linear infinite;
}

/*
 * rotateSpinner keyframe
 * Used by .button-loading-spinner and #loading-image::after.
 * A single 0→360° rotation is all that is needed for a spinner.
 * "linear" easing keeps the rotation speed constant (no easing in/out).
 */
@keyframes rotateSpinner {
	to { transform: rotate(360deg); }
}


/* ============================================================
   14. INLINE ERROR ALERT  (.inline-error-alert)

   A warning box that appears directly below the form fields when
   the server returns a login error (wrong password, locked account, etc.)
   or when client-side validation fails.

   WHY display: none by default?
   The alert should not take up space when there is no error. JavaScript
   toggles it visible by adding the class "visible" (display: block).

   Colour rationale:
   ─ background: #fdfaf1 — warm off-white, associates with caution/warning
   ─ border: #fdeeb9     — pale yellow border, reinforces warning feel
   ─ color: #b22727      — dark red text, communicates error severity clearly
   These colours are distinct from the brand green, so users immediately
   understand this is an error state, not a normal UI element.
   ============================================================ */
/*
 * 14a. AUTH MESSAGE SLOT (.auth-message-slot)
 *
 * A wrapper that reserves vertical space for the error alert box.
 * This ensures that when an error appears, the "Sign In" button does
 * not jump downward, keeping the UI height stable.
 *
 * min-height: 62px is calculated to fit the 44px box + spacing.
 */
.auth-message-slot {
	min-height: 62px;
	margin-top: 20px;
	display: flex;
	align-items: center;
	justify-content: center;
}

.auth-message-slot.mb-20 {
	margin-bottom: 20px;
}

.inline-error-alert {
	display: none;
	padding: 10px 14px;
	background: #fdfaf1;
	border: 1px solid #fdeeb9;
	border-radius: 8px;
	font-size: 1.25rem;
	color: #b22727;
	text-align: center;
}

/*
 * Selective logic: only elements in the slot maintain their space when hidden.
 */
.auth-message-slot .inline-error-alert {
	display: block !important;
	visibility: hidden;
	opacity: 0;
	margin-top: 0 !important;
	transition: opacity 0.2s ease-in-out;
}

.auth-message-slot .inline-error-alert.is-visible {
	visibility: visible;
	opacity: 1;
}

/* Modifier: adds bottom margin when the alert appears above other elements
   (used in OTP/TOTP forms where spacing is tighter) */
.inline-error-alert.mb-20 { margin-bottom: 20px !important; }


/* ============================================================
   15. RESET-PASSWORD MODAL

   Structure:
   ┌─ .modal-backdrop-overlay (full screen) ──────────────┐
   │  ┌─ .modal-dialog-card (centred card) ─────────────┐ │
   │  │  ┌─ .modal-header-bar ────────────────────────┐ │ │
   │  │  │  Title              [× close button]        │ │ │
   │  │  └────────────────────────────────────────────┘ │ │
   │  │  ┌─ .modal-scrollable-body ───────────────────┐ │ │
   │  │  │  (form fields: current/new/confirm password)│ │ │
   │  │  └────────────────────────────────────────────┘ │ │
   │  │  ┌─ .modal-action-footer ─────────────────────┐ │ │
   │  │  │                      [Save Password button] │ │ │
   │  │  └────────────────────────────────────────────┘ │ │
   │  └──────────────────────────────────────────────────┘ │
   └──────────────────────────────────────────────────────┘
   ============================================================ */

/*
 * Full-screen darkened backdrop overlay
 *
 * Covers the entire viewport and dims the sign-in page behind it.
 * This draws the user's full attention to the modal dialog.
 *
 * display: none by default — JS adds class "active" to show it.
 *
 * backdrop-filter: blur(8px) blurs the content behind the overlay.
 * This creates a focused "frosted glass" effect that makes it clear
 * the page behind is temporarily inactive.
 *
 * z-index: 10000 ensures the overlay renders above all other page
 * content, including the login card (z-index: 10) and the frosted card.
 */
.modal-backdrop-overlay {
	display: none;
	position: fixed;
	inset: 0;
	z-index: 10000;
	background: rgba(0, 0, 0, 0.45);
	backdrop-filter: blur(8px);
	-webkit-backdrop-filter: blur(8px);
	align-items: center;
	justify-content: center;
}

/* JS toggles this class to display the overlay as a flex container
   (needed for centering the modal dialog card inside it) */
.modal-backdrop-overlay.active {
	display: flex !important;
}

/*
 * The white modal dialog card
 *
 * max-width: 500px constrains the form to a comfortable reading width
 * on large screens. On small screens, width: 100% with the parent's
 * padding keeps it from touching the screen edges.
 *
 * overflow: hidden clips the header's background-colour to respect
 * the 20px rounded corners of this card.
 *
 * box-shadow creates a strong, layered shadow that separates the
 * modal card clearly from the blurred backdrop behind it.
 */
.modal-dialog-card {
	width: 100%;
	max-width: 500px;
	background: #fff;
	border-radius: 20px;
	overflow: hidden;
	box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
	position: relative;
}

/*
 * Modal header bar: title on the left, close button on the right.
 *
 * !important overrides Bootstrap's .modal-header rules which can set
 * display: block and misalign the title and close button. Explicitly
 * setting display: flex with space-between ensures consistent layout.
 */
.modal-header-bar {
	border-bottom: 1px solid #edf2f7;
	padding: 16px 24px;
	display: flex !important;
	align-items: center !important;
	justify-content: space-between !important;
}

/* Modal title typography — heavier weight (800) for strong visual anchoring */
.modal-title-text {
	font-size: 1.5rem;
	font-weight: 800;
	color: #1e293b;
	margin: 0;
}

/*
 * Circular close (×) button in the top-right corner.
 *
 * The circular shape is achieved with border-radius: 50% on a square
 * (32×32px) element. The × character is the button's text content.
 *
 * The grey background (#e2e8f0) darkens on hover (#cbd5e1) to give
 * clear visual feedback that the button is interactive.
 */
.modal-close-button {
	border: none !important;
	background: #e2e8f0;
	width: 32px;
	height: 32px;
	border-radius: 50%;
	color: #64748b;
	font-size: 16px;
	display: flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	transition: all 0.2s;
	outline: none;
}

.modal-close-button:hover {
	background: #cbd5e1;
	color: #1e293b;
}

/*
 * Scrollable modal body
 * Contains the password change form fields.
 * padding: 24px gives fields room to breathe inside the modal card.
 */
.modal-scrollable-body {
	padding: 24px;
}

/*
 * Modal action footer (Save Password button row)
 *
 * background: #f8fafc — light grey distinguishes this area from the
 * white form body above it, grouping the action button visually.
 *
 * justify-content: flex-end right-aligns the Save button. This follows
 * common modal UX patterns where the primary action is on the right.
 *
 * !important overrides Bootstrap's .modal-footer styles which can
 * add unexpected borders or padding.
 */
.modal-action-footer {
	padding: 16px 24px;
	background: #f8fafc;
	border-top: 1px solid #edf2f7;
	display: flex !important;
	justify-content: flex-end !important;
}


/* ============================================================
   16. PASSWORD REQUIREMENTS CHECKLIST

   Displayed below the "New Password" input field in the reset modal.
   Shows a live checklist of password rules (length, uppercase, number, etc.)
   that updates in real-time as the user types.

   Each list item has either class .requirement-met or .requirement-unmet.
   JavaScript swaps these classes as each rule passes or fails validation.

   .requirement-met   — green ✔ prefix: requirement is satisfied
   .requirement-unmet — muted red ✖ prefix: requirement not yet met
   ============================================================ */

/*
 * Container card for the requirements list.
 * background: #f8fafc (light grey) visually separates the requirements
 * from the input above it, grouping them as metadata about the field.
 * margin-top: 15px creates a gap below the new-password input field.
 * Revealed by JS when the user clicks into the new-password field.
 */
.password-requirements-box {
	margin-top: 15px;
	padding: 18px;
	background: #f8fafc;
	border: 1px solid #f1f5f9;
	border-radius: 12px;
	font-size: 1.15rem;
}

/* Bold heading inside the requirements box */
.requirements-box-title {
	font-weight: 700;
	margin-bottom: 10px;
	color: var(--text-color-dark);
}

/*
 * A requirement that the user has satisfied.
 * The ✔ is generated by ::before so it doesn't need to be in the HTML.
 * This keeps the markup clean and allows JS to only swap the class name.
 */
.requirement-met {
	color: green;
}
.requirement-met::before {
	content: "✔ ";
}

/*
 * A requirement that has not yet been satisfied.
 * Muted red (#c66c6c) is less alarming than bright red — the user
 * hasn't done anything wrong yet, they just haven't typed enough.
 * The ✖ prefix (not ✗) is visually lighter and less aggressive.
 */
.requirement-unmet {
	color: #c66c6c;
}
.requirement-unmet::before {
	content: "✖ ";
}

/*
 * General red colour class used for required-field indicators
 * (e.g. asterisks next to mandatory field labels).
 */
.required-field-indicator {
	color: #c66c6c;
}


/* ============================================================
   17. PAGE FORM FOOTER  (.page-form-footer, .copyright-text)

   Sits at the bottom of the right panel inside .form-content-wrapper.
   The copyright year is dynamically injected by signin.js into #id_rights.

   WHY margin-top: auto?
   .form-content-wrapper is a flex column. margin-top: auto on a flex
   child pushes that child to the bottom of the flex container, filling
   any remaining space above it with empty margin. This creates a footer
   that sticks to the bottom of the panel regardless of how much form
   content is above it — without needing position: absolute.

   border-top: 1px solid rgba(76, 174, 53, 0.12)
   A very subtle green divider line separates the footer from the form
   content above it, giving the footer its own visual zone.
   ============================================================ */
.page-form-footer {
	margin-top: auto;
	padding-top: 32px;
	border-top: 1px solid rgba(76, 174, 53, 0.12);
	text-align: center;
}

.copyright-text {
	font-size: 1.4rem;
	color: var(--text-color-dark);
}


/* ============================================================
   18. UTILITY / HELPER CLASSES

   Small, single-purpose classes that can be added to any element
   to apply a specific style without needing a dedicated CSS rule.
   ============================================================ */

/*
 * .reset-password-link
 * The "Reset Password" anchor shown to the user when their password
 * has expired (server returns code=3 in the auth response).
 * Hidden by default — JS calls .style.display = 'block' to reveal it.
 * Blue colour (#2563eb) clearly distinguishes it from the green brand
 * palette, signalling it is an external action (link), not a button.
 */
.reset-password-link {
	display: none;
	color: #2563eb;
	text-decoration: underline;
	cursor: pointer;
	font-size: 1.2rem;
}

/* Quick spacing utilities (used via class="" in HTML templates) */
.mb-20 { margin-bottom: 20px; }
.mb-0  { margin-bottom: 0 !important; }

/*
 * .field-validation-error-text
 * An inline error message displayed immediately below a specific input
 * field when that field's validation fails (e.g. "Passwords do not match").
 * Hidden by default; JS adds display: block when validation fails.
 * font-size: 1rem is smaller than the label, reinforcing its secondary role.
 */
.field-validation-error-text {
	display: none;
	color: #ef4444;
	font-size: 1rem;
	margin-top: 4px;
}

/*
 * .modal-save-password-button
 * Modifier class applied to .submit-signin-button when it appears inside
 * the modal footer. The default button is full-width (100%), but inside
 * the modal's right-aligned footer it should be compact.
 * width: auto shrinks the button to its content width.
 * min-width: 150px prevents it from becoming too small to read.
 * margin: 0 !important overrides the margin-top: 10px from .submit-signin-button.
 */
.modal-save-password-button {
	width: auto;
	min-width: 150px;
	padding: 10px 24px;
	font-size: 1.25rem;
	margin: 0 !important;
}

/*
 * .password-field-eye-icon
 * A Font Awesome eye icon used inside password input wrappers in the
 * reset-password modal. This is an older implementation pattern —
 * newer password fields use the .password-toggle-button SVG approach.
 *
 * Positioned on the right side of the input wrapper so it does not
 * overlap with typed text. top: 40% + translateY(-50%) centres it
 * vertically with the same optical correction as .input-left-icon.
 */
.password-field-eye-icon {
	position: absolute;
	right: 15px;
	top: 40%;
	transform: translateY(-50%);
	font-size: 16px;
	cursor: pointer;
	color: #aac8a6;
}


/* ============================================================
   19. FULL-PAGE LOADING OVERLAY  (#loading-image)

   A fixed overlay that blocks all user interaction while an async
   request is in progress (login attempt, OTP verify, password save).
   This prevents users from submitting the form multiple times.

   WHY z-index: 20000?
   The reset-password modal has z-index: 10000. The loading overlay
   needs to appear above the modal when a password-save request is
   pending, so z-index: 20000 ensures it always sits at the top.

   background: rgba(240, 248, 237, 0.55)
   A light green-tinted semi-transparent overlay that visually connects
   with the brand colour palette. At 0.55 opacity it dims the page
   without completely hiding it.

   backdrop-filter: blur(4px)
   A light blur (less than the modal's 8px) so the page behind is
   still vaguely visible but clearly "inactive".

   The spinning ring is generated entirely in CSS using the ::after
   pseudo-element — no spinner image or SVG needed.
   ============================================================ */
#loading-image {
	display: none;
	position: fixed;
	inset: 0;
	z-index: 20000;
	background: rgba(240, 248, 237, 0.55);
	backdrop-filter: blur(4px);
}

/*
 * The spinner ring, generated as a pseudo-element.
 *
 * HOW IT IS CENTRED:
 *   position: absolute + top: 50% + left: 50%
 *   → places the top-left corner of the ring at the viewport centre
 *   margin: -16px 0 0 -16px
 *   → shifts the element left and up by half its size (16px = 32px ÷ 2)
 *   → net effect: the ring's centre is at the viewport centre
 *
 * Using margin instead of transform: translate(-50%, -50%) here is an
 * older but reliable technique that works in all browsers including IE11.
 *
 * HOW THE SPINNING RING IS DRAWN:
 *   border: 2.5px solid rgba(76, 174, 53, 0.2)  → faint green ring (the "track")
 *   border-top-color: var(--brand-primary-green) → solid green arc (the "arm")
 *   As rotateSpinner rotates the element 360°, the arm appears to chase itself.
 */
#loading-image::after {
	content: '';
	position: absolute;
	top: 50%;
	left: 50%;
	width: 32px;
	height: 32px;
	margin: -16px 0 0 -16px;
	border: 2.5px solid rgba(76, 174, 53, 0.2);
	border-top-color: var(--brand-primary-green);
	border-radius: 50%;
	animation: rotateSpinner 0.8s linear infinite;
}

/*
 * Error message displayed at the top of the reset-password modal body
 * when the server returns an error (e.g. incorrect current password).
 * Injected and shown by JavaScript via the #pass_reset_msg element.
 */
#password_reset_error_message {
	text-align: center;
	color: #b22727;
	padding: 10px 10px 5px 5px;
}


/* ============================================================
   20. GLOBAL ELEMENT RESETS

   These rules complement the universal reset (section 1) by targeting
   specific HTML elements that browsers style distinctly by default.
   Without these, Bootstrap or browser defaults could override the
   design system's intent.

   WHY are these at the bottom of the file instead of the top?
   They are placed after the component rules so that any component-level
   override (using !important or higher specificity) takes precedence.
   The global reset at the top (section 1) is for margin/padding;
   these resets are for semantic/typographic defaults.
   ============================================================ */

/* Remove default browser margins from all heading levels.
   Headings are styled via .form-title-heading and component-specific rules. */
h1, h2, h3, h4, h5, h6 {
	margin: 0;
	padding: 0;
}

/* Second box-sizing declaration — a safe duplicate for clarity */
* {
	box-sizing: border-box;
}

/* Remove default list bullets and indentation.
   Lists are used for the password requirements checklist (section 16)
   and Bootstrap nav components; plain styling is set per-component. */
ul, li, ol {
	margin: 0;
	padding: 0;
	list-style: none;
}

/* Remove underlines from all anchors by default.
   Specific links that should be underlined (e.g. .reset-password-link)
   set text-decoration: underline explicitly. */
a {
	text-decoration: none;
}

/* Prevent images from overflowing their container.
   max-width: 100% ensures images scale down on small screens. */
img {
	max-width: 100%;
}

/* Zero out margin/padding on common inline and block elements
   that browsers sometimes add spacing to by default. */
span, strong, p, br, form, section,
footer, header, caption, nav, figure, small {
	margin: 0;
	padding: 0;
}

/*
 * Override Bootstrap's default <label> font-weight.
 * Bootstrap 3/4 sets label { font-weight: bold } globally.
 * This override resets labels to light weight; individual labels
 * that need bold (e.g. .input-label-text) apply font-weight: 700
 * with !important to win the specificity battle.
 */
label {
	font-weight: 100 !important;
}

/*
 * .field-required-message
 * A validation message shown inside the form when the user tries to
 * submit without filling a required field. Hidden by default;
 * JS sets display: block when the field fails empty-check validation.
 */
.field-required-message {
	color: #a94442;
	display: none;
}

/*
 * Hide the Bootstrap-generated .modal-footer element entirely.
 * The custom .modal-action-footer replaces it for the reset-password modal.
 * !important ensures this wins over Bootstrap's display: flex on .modal-footer.
 */
.modal-footer {
	display: none !important;
}

/*
 * Bootstrap sometimes inserts ::before and ::after pseudo-elements
 * inside .modal-header and .modal-footer for clearfix and flexbox
 * alignment purposes. These can misalign the custom modal layout.
 * Force them hidden.
 */
.modal-header::before,
.modal-header::after {
	display: none !important;
}
.modal-footer::before,
.modal-footer::after {
	display: none !important;
}

/*
 * Override Bootstrap's .modal-header styles.
 * Bootstrap 3/4 sets display: block on .modal-header, which prevents
 * flex alignment of the title and close button. Force flex layout
 * with space-between so the close button always sits on the right.
 */
.modal-header {
	width: 100% !important;
	display: flex !important;
	justify-content: space-between !important;
}

/* Server-side error and warning messages rendered inside #msg */
#msg {
	width: 100%;
}

/*
 * Override Bootstrap's .alert-warning text colour.
 * Bootstrap uses a brown/amber colour for warnings. On this page,
 * warning messages are authentication errors and should use red
 * to clearly communicate failure.
 */
.alert-warning {
	color: #b22727 !important;
}

/*
 * Style all submit buttons across the page consistently.
 * Any <button type="submit"> that does not use .submit-signin-button
 * will still receive the brand green background and white text.
 * cursor: pointer ensures the hand cursor appears on hover.
 */
button[type="submit"] {
	background-color: #2a9f00;
	color: white;
	cursor: pointer;
}


/* ============================================================
   21. RESPONSIVE BREAKPOINTS — MOBILE

   Target: screens ≤ 720px wide (phones and narrow browser windows)

   At this width, the two-column layout (55% left / 45% right) becomes
   too narrow to be readable. The panels are stacked vertically instead.

   Design decisions for mobile:
   ─ The decorative left panel becomes a shorter header at the top.
     It shows the brand imagery but doesn't compete with the form.
   ─ The form panel takes full width below it.
   ─ Padding is reduced to recover space on the narrow screen.
   ─ The image stack is scaled down proportionally.
   ============================================================ */
@media (max-width: 720px) {

	/*
	 * Stack the card vertically.
	 * flex-direction: column places the left panel on top and
	 * the right panel below it (source order is preserved).
	 * max-width: 440px prevents the stacked card from being too wide
	 * on large tablets in portrait mode.
	 * min-height: unset removes the desktop 560px minimum so the card
	 * shrinks naturally to its content height.
	 */
	.login-card {
		flex-direction: column;
		max-width: 440px;
		min-height: unset;
		border-radius: 20px;
	}

	/*
	 * Left panel: full width on mobile, rounded only on top corners.
	 * The bottom corners are square because they connect to the form panel.
	 * min-height: 300px prevents the panel from collapsing if there is
	 * little image content visible.
	 */
	.decorative-left-panel {
		width: 100%;
		border-radius: 20px 20px 0 0;
		padding: 36px 28px;
		min-height: 300px;
	}

	/* Right panel: full width, reduced padding for narrow screens */
	.form-right-panel {
		width: 100%;
		padding: 36px 28px 32px;
	}

	/*
	 * Update the dot-grid's border-radius to match the stacked card shape.
	 * On desktop it was 0 24px 24px 0 (right side of a horizontal card).
	 * On mobile it becomes 0 0 20px 20px (bottom of a vertical card).
	 */
	.form-right-panel::before {
		border-radius: 0 0 20px 20px;
	}

	/* Scale the image stack to fit the narrower mobile panel */
	.image-stack-container {
		width: 240px;
		height: 240px;
	}

	/* Scale the product image wrapper proportionally */
	.product-image-wrapper {
		width: 180px;
		height: 180px;
	}
}
