/*
 * Loop Forms - Base Styles (De-duplicated & Coherent CSS)
 * Provides structural and presentational styling for the dark slide-in modal form.
 */

:root {
    /* SCSS Variables converted to CSS Custom Properties */
    --lf-modal-width: 550px;
    --lf-modal-z-index: 8005;
    --lf-modal-container-z-index: 8006;
    --lf-modal-transition-timing: cubic-bezier(0.25, 0.8, 0.25, 1);
}

/* --- Core Modal Positioning --- */

.loop-forms-modal {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 8005;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.3s ease, visibility 0.3s ease;
    background: rgba(0, 0, 0, 0.65);
    backdrop-filter: blur(4px);
}

.loop-forms-modal.loop-forms-modal--active {
    opacity: 1;
    visibility: visible;
}

.lf-overlay {
    position: absolute;
    width: 100%;
    height: 100%;
    cursor: pointer;
}

/* --- Container (Modal Drawer) Styling and Functionality --- */

/* SHARED — everything true of the dialog whatever shape it takes. No
   positioning here: each presentation mode declares its own below, so no mode
   ever has to undo another's. See "PRESENTATION MODES" at the end of the file. */
.lf-container {
    background: #333; /* Main background */
    overflow: hidden;
    z-index: 8006;
    display: flex;
    flex-direction: column;
    padding: 56px;
    box-sizing: border-box;
}

@media (max-width: 768px) {
    .lf-container {
        padding: 24px;
    }
}

/* DRAWER — the full-height panel pinned to the right. The established look on
   G2, G2X and Lux.

   Scoped with :not(.lf-present-centred) rather than .lf-present-drawer on
   purpose: a page served from a cache BEFORE presentation classes existed
   carries no lf-present-* class at all, and this still matches it, so those
   pages keep the drawer instead of losing their positioning. Positive scoping
   would leave them unpositioned until the page cache rolled over.

   Specificity is (0,3,0). Lux scopes its own overrides with an ID
   (#loop-forms-modal.lf-surface-g2lux-exp, (1,2,0)), so it still out-ranks
   this — checked before the rules were tightened. */
.loop-forms-modal:not(.lf-present-centred) .lf-container {
    position: fixed;
    top: 0;
    right: 0;
    /* Reads the :root variable so a mode or surface can retune the width
       without overriding the whole rule. Fallback is the value this was
       hardcoded to, so nothing changes if the variable ever goes. */
    width: var(--lf-modal-width, 550px);
    height: 100vh;
    max-height: 100vh;
    transform: translateX(100%); /* Start position: Off-screen */
    transition: transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
    box-shadow: -8px 0 32px rgba(0, 0, 0, 0.25);
}

@media (max-width: 768px) {
    .loop-forms-modal:not(.lf-present-centred) .lf-container {
        width: 100%;
    }
}

.loop-forms-modal:not(.lf-present-centred).loop-forms-modal--active .lf-container {
    transform: translateX(0); /* Slide-in on active */
}

/* --- Header, Close Button, and Body --- */

.lf-header {
    position: relative;
    padding-bottom: 20px;
    margin-bottom: 10px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.lf-title {
    margin: 0;
}

.lf-close {
    position: absolute;
    top: 0;
    right: 0;
    background: transparent;
    border: none;
    cursor: pointer;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.2s ease;
}

.lf-form .submit-area .button svg {
    stroke: #ffffff;
}

.lf-close svg {
    stroke: #fff; /* Force close icon to white */
    width: 24px;
    height: 24px;
    transition: color 0.2s ease;
}

.lf-close:hover svg {
    color: #ccc; /* Subtle hover effect on icon */
}

.lf-body {
    /* flex: 1; */
    overflow-y: auto;
    /* display: flex; */
    /* flex-direction: column; */
    /* min-height: 0; */
    
    /* Scrollbar hiding (structural) */
    scrollbar-width: none;
    -ms-overflow-style: none;
}

.lf-intro {
    margin-bottom: 20px;
}

/* --- Form Layout and Fields --- */

.loop-forms {
    display: flex;
    flex-direction: column;
    height: 100%;
}

.loop-forms .fields {
    flex: 1;
    overflow-y: auto;
    padding-bottom: 20px;
}

/* Base Label Styling (Hides non-checkbox labels for placeholder use) */
.loop-forms label {
    display: block;
    margin-bottom: 20px;
    position: relative;
    font-size: 0;
    /* color: transparent; */
}

.loop-form__success-container {
    text-align:center; 
}

/* Input, Textarea, Select, and Date Field Styling */
.loop-forms-modal .loop-forms label input:not([type="checkbox"]),
.loop-forms-modal .loop-forms label textarea,
.loop-forms-modal .loop-forms label select,
.loop-forms-modal .loop-forms label input[type="date"] {
    display: block;
    width: 100%;
    margin-top: 5px;
    padding: 12px 10px;
    border: 2px solid #333; 
    border-radius: 4px;
    font-size: 16px;
    background: transparent;
    /* Fallback is the value this was hardcoded to, and :root declares the same,
       so an unset site computes exactly #333 as before. */
    color: var(--loop-forms-input-text, #333);
    box-sizing: border-box;
    /* Date specific structural rule */
    position: relative;
    cursor: pointer;
}

/* Input Focus State */
.loop-forms label input:focus,
.loop-forms label textarea:focus,
.loop-forms label select:focus {
    outline: none;
    box-shadow: 0 0 0 1px #fff;
}

.loop-forms label textarea {
    resize: vertical;
    min-height: 80px;
}

/* --- Date Input Overrides for Custom Calendar Icon --- */

.loop-forms label input[type="date"]::-webkit-calendar-picker-indicator {
    /* Makes the entire input clickable for calendar popup, hiding native icon */
    opacity: 0;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 100%;
    cursor: pointer;
    z-index: 2;
}

/* Style the custom SVG icon white (inside the relative div wrapper) */
.loop-forms label div[style*="position: relative"] svg {
    color: #fff !important; 
    stroke: #fff;
}

/* Labels that need visible text (e.g. date picker with no placeholder) */
.loop-forms label.has-visible-label {
    font-size: 14px;
    color: #333;
}

.loop-forms label.has-visible-label .label-text {
    display: block;
    font-size: 14px;
    font-weight: 500;
    margin-bottom: 4px;
}

/* --- Checkbox and Fieldset Styling --- */

fieldset {
    border: none;
    padding: 0;
    margin: 0;
    min-width: 0;
}

.loop-forms .service-legend {
    font-size: 14px;
    font-weight: 600;
    color: #333;
    margin-bottom: 12px;
    padding: 0;
    display: block;
    width: 100%;
    float: none;
}



/* Fieldset/Legend for time slots (Visibility overrides) */
.loop-forms .fieldset.time-slots-fieldset {
    display: block;
    margin-bottom: 20px;
}

.loop-forms legend {
    margin-bottom: 10px;
}

.loop-forms .fieldset.time-slots-fieldset legend {
    display: block;
    font-size: 16px;
    margin-bottom: 10px;
}

/* Time Slot and Consent Checkboxes (Visible Labels) */
.loop-forms label.checkbox {
    display: flex;
    align-items: flex-start;
    cursor: pointer;
    margin-bottom: 10px;
    font-size: 16px; 
}

.loop-forms label.checkbox input[type="checkbox"] {
    flex-shrink: 0;
    margin: 3px 10px 0 0;
    width: 18px;
    height: 18px;
    cursor: pointer;
}

.loop-forms label.checkbox .service-checkbox {
    color:red;
}

.loop-forms label.checkbox .checkbox-text {
    font-size: 16px;
    line-height: 1.4;
}

.loop-forms label.checkbox .checkbox-text a {
    text-decoration: underline;
}

/* First two service options - Always in a row (50/50 or 100% if only one) */
.modal-type-generic-valuation .service-checkboxes-first-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0;
    margin-bottom: 10px;
}

/* If only one option in first row, take full width */
.modal-type-generic-valuation .service-checkboxes-first-row:has(.checkbox:only-child) {
    grid-template-columns: 1fr;
}

/* Remaining options - Always full width */
.modal-type-generic-valuation .service-checkboxes-remaining .checkbox {
    margin-bottom: 10px;
}

/* Mobile - stack first row vertically */
@media (max-width: 600px) {
    .modal-type-generic-valuation .service-checkboxes-first-row {
        grid-template-columns: 1fr;
    }
}

/* Divider & Note */
.loop-forms .divider {
    border: none;
    height: 1px;
    background: #666;
    margin: 20px 0;
}

.loop-forms .note {
    font-size: 14px;
    color: #ccc;
    margin-bottom: 20px;
}

/* --- Submit Button Area --- */

.submit-area {
    margin-top: auto;
    padding-top: 20px;
    margin-bottom: 50px;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.submit-area .button {
    width: 100%;
}

.submit-area .button svg {
    margin-left: 8px;
    transition: transform 0.2s ease;
}

.submit-area .button:hover svg {
    transform: translateX(2px);
}

/* =======================================================================
   RESPONSIVE DESIGN & THEME OVERRIDES
   ======================================================================= */

/* Desktop-only enhanced shadow (above 767px) */
@media (min-width: 768px) {
    .lf-container {
        box-shadow: -12px 0 48px rgba(0, 0, 0, 0.3);
    }
}

/* Mobile adjustments (767px and below) */
@media (max-width: 767px) {
    .lf-container {
        width: 100vw;
        box-shadow: none; /* Remove shadow on mobile */
    }
    
    .loop-forms-modal {
        backdrop-filter: blur(2px); /* Reduced blur on mobile */
    }
}

/* =======================================================================
   THEME OVERRIDE STYLES - Match Flyout Menu Design
   ======================================================================= */

/* CSS Variables for theme integration.
 *
 * A theme sets these and the modal recolours — no selector overrides needed.
 *
 * WHY THREE OF THEM HAVE NO DEFAULT HERE
 * --------------------------------------
 * Four of these variables were declared but never read by anything (reported
 * by the g2com theme team, 2026-07-31: "setting them looks correct and does
 * nothing"). They are wired up now, but three could not keep a default value.
 *
 * The plugin has never set a text colour on the dialog, nor any colour on the
 * submit button — both inherit or come from the theme. Giving those a default
 * here would apply it to every site that hasn't opted in, repainting modals
 * across the fleet. Left undeclared, the `var(--x, <fallback>)` fallbacks take
 * over and each computes to exactly what the site renders today.
 *
 * Set any of them from a theme and it takes effect. See the consumers marked
 * "theme variable hook" below.
 */
:root {
    /* Safe to default — each already matches what the plugin renders today. */
    --loop-forms-bg: #333;
    --loop-forms-overlay: rgba(0, 0, 0, 0.65);
    --loop-forms-input-bg: #fff;
    --loop-forms-input-text: #333;
    --loop-forms-border: rgba(255, 255, 255, 0.1);

    /* --loop-forms-text is intentionally NOT defaulted — see the note above.
     *
     * There is deliberately no --loop-forms-button-bg / --loop-forms-button-text.
     * The submit button is theme-owned: it renders as the site's primary button
     * and follows Giro Settings → Buttons. See the note by the theme variable
     * hooks below for why adding them back doesn't work.
     */
}

/* Theme-aware styling that matches flyout menu */
.lf-container {
    background: var(--loop-forms-bg);
}

.loop-forms-modal {
    background: var(--loop-forms-overlay);
}

.lf-header {
    border-bottom: 1px solid var(--loop-forms-border);
}



.lf-close:hover {
    background: rgba(255, 255, 255, 0.2);
}

.lf-intro {
    opacity: 0.9;
}

/* Form field styling */
.loop-forms-modal input,
.loop-forms-modal textarea,
.loop-forms-modal select {
    background: var(--loop-forms-input-bg);
    border: 2px solid rgba(255, 255, 255, 0.1);
}

.loop-forms-modal input:focus,
.loop-forms-modal textarea:focus,
.loop-forms-modal select:focus {
    border-color: rgba(255, 255, 255, 0.3);
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.1);
}




/* Submit button area */
.submit-area {
    border-top: 1px solid var(--loop-forms-border);
}

.submit-area .button svg {
    stroke: currentColor;
}

/* ---------------------------------------------------------------------------
   Theme variable hooks — dialog text and submit button.
   ---------------------------------------------------------------------------
   Wrapped in :where() ON PURPOSE. :where() contributes ZERO specificity, so
   any existing theme rule — even a bare `.button { background: gold }` at
   (0,1,0) — still wins. That matters because the plugin has never coloured
   these: the dialog's text inherits and the button is entirely theme-styled.
   A normally-specific rule here would out-rank those themes and repaint
   modals across the fleet.

   So the behaviour is:
     theme already has a rule    -> theme wins, nothing changes
     theme sets only the variable -> the variable applies
     theme does neither          -> the fallback computes to today's rendering
   ------------------------------------------------------------------------ */
:where(.lf-container) {
    /* `inherit` is what colour already does when undeclared, so an unset site
       renders identically. Nothing else claims .lf-container's colour, so a
       zero-specificity rule is enough to win here. */
    color: var(--loop-forms-text, inherit);
}

/* NO submit-button colour hook here, deliberately.
 *
 * There was briefly a :where(.submit-area .button) rule reading
 * --loop-forms-button-bg / --loop-forms-button-text. It could never fire. The
 * button ships as class="button button--primary", and every Giro theme styles
 * `.button` at (0,1,0), which beats :where()'s (0,0,0) — so the variables
 * looked settable and silently did nothing (reported by the g2com theme team,
 * 2026-07-31).
 *
 * Rather than escalate specificity to out-rank the themes, the button is
 * TREATED AS THEME-OWNED ON PURPOSE. It should render as the site's primary
 * button and follow Giro Settings → Buttons, rather than the modal becoming a
 * second source of truth for the same colour.
 *
 * The variables are therefore gone rather than left unreachable — an option
 * that looks available and never works is worse than no option. If a future
 * surface genuinely needs the submit button variable-driven, it needs either
 * its own class the themes don't style, or normal specificity plus a migration
 * agreed with every theme. Don't just add the rule back.
 */

/* =======================================================================
   PROPERTY MATCHING FORM SPECIFIC STYLES
   ======================================================================= */

/* Fix input text color override for property matching form in sections */
section.module form.loop-form--loop-forms-property-matching label input,
section.module form.loop-form--loop-forms-property-matching label textarea, 
section.module form.loop-form--loop-forms-property-matching label select {
    color: #333;
}

/* Fix checkbox text color override for property matching form in sections */
section.module form.loop-form--loop-forms-property-matching .checkbox .checkbox-text {
    color: #333;
}

/* Two-column form rows for property matching form */
.loop-form--loop-forms-property-matching .form-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 15px;
}

@media (max-width: 768px) {
    .loop-form--loop-forms-property-matching .form-row {
        grid-template-columns: 1fr;
        gap: 0;
    }
}

/* Spacing between checkboxes for property matching form */
.loop-form--loop-forms-property-matching label.checkbox {
    margin-bottom: 15px!important;
}

/* Consent section styling */
.loop-form--loop-forms-property-matching .consent-section {
    font-size: 14px;
}

.loop-form--loop-forms-property-matching .consent-title {
    font-size: 15px;
    font-weight: bold;
    margin: 0 0 20px 0;
}

/* Section title spacing */
.loop-form--loop-forms-property-matching h4 {
    margin-bottom: 24px;
}

/* Lighter text for consent section */
.loop-form--loop-forms-property-matching .consent-section .checkbox-text,
.loop-form--loop-forms-property-matching .consent-section .privacy-notice {
    opacity: 0.8;
}

/* =======================================================================
   JOIN MAILING LIST (footer / VIP signup) — structure only; theme polishes
   ======================================================================= */

.loop-form--loop-forms-join-mailing-list.loop-form-join-mailing-list {
    display: block;
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
}

.loop-form--loop-forms-join-mailing-list .loop-form-join-mailing-list-fields {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px 16px;
    width: 100%;
}

@media (max-width: 768px) {
    .loop-form--loop-forms-join-mailing-list .loop-form-join-mailing-list-fields {
        grid-template-columns: 1fr;
    }
}

/* Visually hidden labels; placeholders carry visible cues (theme/footer may override). */
.loop-form--loop-forms-join-mailing-list .loop-form-join-mailing-list-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.loop-form--loop-forms-join-mailing-list .loop-form-join-mailing-list-field {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.loop-form--loop-forms-join-mailing-list .loop-form-join-mailing-list-input {
    padding: 12px 18px;
    border: 2px solid #d1d5db;
    border-radius: 9999px;
    text-transform: uppercase;
}

.loop-form--loop-forms-join-mailing-list .loop-form-join-mailing-list-input:focus {
    outline: none;
    border-color: #9ca3af;
    box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.06);
}

.loop-form--loop-forms-join-mailing-list .loop-form-join-mailing-list-submit-wrap {
    width: 100%;
    margin-bottom: 12px;
}

.loop-form--loop-forms-join-mailing-list .loop-form-join-mailing-list-submit-wrap .submit-button {
    width: 100%;
    max-width: 100%;
    min-width: 0;
    box-sizing: border-box;
    justify-content: center;
    text-transform: uppercase;
}

.loop-form--loop-forms-join-mailing-list .loop-form-join-mailing-list-acknowledgement {
    margin: 0 0 4px 0;
    font-size: 10px;
    line-height: 1.45;
    font-weight: 400;
    text-transform: none;
    letter-spacing: normal;
    color: inherit;
}

.loop-form--loop-forms-join-mailing-list .loop-form-join-mailing-list-success {
    margin-top: 12px;
}

.loop-form--loop-forms-join-mailing-list .loop-form-join-mailing-list-error {
    font-style: normal;
    font-weight: 600;
    color: #b91c1c;
}

/* =====================================================================
   Contact Note form ([loop_contact_note] / loop-forms-contact-note.php)
   BASE structure only — a usable skeleton on ANY theme. Brand styling is
   layered per-surface (e.g. the Lux skin in loop-forms-lux.css scopes to
   .lf-contact-note.lf-surface-g2lux-exp). Keep this file free of brand
   colours/fonts so every theme starts from a clean, unbroken form.
   ===================================================================== */

/* This is an INLINE page form, not a modal. The base .loop-forms rules are
   built for the drawer (fill-height flex column, scrolling .fields, submit
   pinned to the bottom with margin-top:auto). Inline, those leave a big
   empty gap above the submit and an internal scrollbar — so undo them here.
   Also force left alignment so a centred theme container can't centre it. */
.lf-contact-note {
    text-align: left;
    /* Fill (and never exceed) whatever column/container it's dropped into —
       the page builder controls the width, not the form. */
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
}

.lf-contact-note .loop-forms {
    height: auto;
}

.lf-contact-note .loop-forms .fields {
    flex: none;
    overflow: visible;
    padding-bottom: 0;
}

.lf-contact-note .submit-area {
    margin-top: 24px;
    margin-bottom: 0;
    padding-top: 0;
    border-top: 0;
}

.lf-contact-note .lf-note__eyebrow {
    display: block;
    margin-bottom: 6px;
    text-transform: uppercase;
    letter-spacing: 0.16em;
    font-size: 12px;
}

.lf-contact-note .lf-note__title {
    margin: 0 0 24px;
}

/* Two-up rows (name/email, phone/postcode) — collapse to one column on
   narrow screens. */
.lf-contact-note .lf-note__row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
    margin-bottom: 16px;
}

/* "Getting in touch about" — chips that wrap onto as many rows as needed. */
.lf-contact-note .lf-note__radios {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.lf-contact-note .lf-note__radio {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
}

.lf-contact-note .lf-note__optional {
    text-transform: none;
    opacity: 0.7;
}

.lf-contact-note .lf-note__footer {
    margin: 16px 0 0;
    font-size: 12px;
    line-height: 1.5;
    opacity: 0.7;
}

@media (max-width: 600px) {
    .lf-contact-note .lf-note__row {
        grid-template-columns: 1fr;
    }
}

/* =====================================================================
   Plugin-injected feedback states — neutral fallbacks
   These elements are created by PLUGIN JS, so the plugin ships their
   baseline styling (doctrine: the plugin owns its own markup's structure
   + neutral chrome; themes repaint freely — theme CSS loads later and
   wins ties). Before this block they relied on THEME files: g2's legacy
   _property-forms.scss styled .loop-form__success, and only on pages
   where the properties bundle loads — leaving AJAX success/error boxes
   unstyled everywhere else (all themes). Greens/reds here are SEMANTIC
   state colours, not client brand.
   - .loop-form__message + __success/__error: injected by frontend.js
     handleAjaxFormSubmission() after inline AJAX submissions.
   - .lf-error: injected by modal-system.js when a modal form fails to
     load.
   ===================================================================== */

.loop-form__message {
    padding: 1rem;
    border-radius: 6px;
    margin-top: 1rem;
    text-align: center;
    font-weight: 500;
}

.loop-form__message.loop-form__success {
    background-color: #ecf7ef;
    border: 1px solid #9fd4ac;
    color: #1e5d2c;
}

.loop-form__message.loop-form__error {
    background-color: #fdf0ef;
    border: 1px solid #f0b6b0;
    color: #8a2620;
}

.lf-error {
    padding: 1rem;
    text-align: center;
    color: #8a2620;
}




/* ============================================================================
   PRESENTATION MODES
   ============================================================================
   How the modal appears is a structural property of the plugin, selected per
   surface by loop_forms_modal_presentation() (inc/surfaces.php), rather than
   something a theme overrides from its own stylesheet. A theme fighting
   .lf-container breaks quietly the first time the drawer is retuned here.

   Everything above describes the DRAWER and is deliberately left unscoped:
   it stays the behaviour for G2, G2X, Lux and any site whose HTML was cached
   before these classes existed. The modes below only ever ADD to that.

   .lf-present-drawer   the default. No rules needed — the base IS the drawer.
                        The class is stamped anyway so a theme can target it.
   .lf-present-centred  a dialog in the middle of the viewport. Used by eXp
                        Commercial (g2com-exp).
   ========================================================================== */

/* --- Centred ------------------------------------------------------------ */

/* The wrapper is already a full-screen fixed overlay with the dim and blur,
   so it only has to become a centring context. Padding keeps the dialog off
   the edges on short viewports and small screens. */
.loop-forms-modal.lf-present-centred {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    box-sizing: border-box;
}

.loop-forms-modal.lf-present-centred .lf-container {
    /* No `position` needed. The drawer's `position: fixed` is scoped behind
       :not(.lf-present-centred), so it never applies here and the element
       simply stays in normal flow, centred by the flex parent above. Nothing
       is being undone — this mode declares only what it wants. */
    width: 100%;
    max-width: var(--lf-modal-width, 550px);

    /* The drawer is full-height by design; a centred dialog is only as tall as
       its content, up to what the viewport allows. */
    height: auto;
    max-height: calc(100vh - 48px);

    border-radius: var(--lf-modal-radius, 16px);
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.30);

    /* Its own entrance: fade and lift. The drawer's translateX animation is
       scoped out along with its positioning, so there is no competing
       transform to fight. */
    transform: translateY(12px) scale(0.98);
    opacity: 0;
    transition:
        transform 0.28s cubic-bezier(0.25, 0.8, 0.25, 1),
        opacity 0.24s ease;
}

.loop-forms-modal.lf-present-centred.loop-forms-modal--active .lf-container {
    transform: translateY(0) scale(1);
    opacity: 1;
}

/* Content scrolls inside the dialog rather than the dialog growing past the
   viewport, which would put the submit button out of reach on a laptop. */
.loop-forms-modal.lf-present-centred .lf-body {
    overflow-y: auto;
}

/* Small screens: use the space, and drop the lift so it doesn't feel jumpy. */
@media (max-width: 768px) {
    .loop-forms-modal.lf-present-centred {
        padding: 16px;
    }
    .loop-forms-modal.lf-present-centred .lf-container {
        max-width: 100%;
        max-height: calc(100vh - 32px);
        transform: translateY(8px) scale(1);
    }
    .loop-forms-modal.lf-present-centred.loop-forms-modal--active .lf-container {
        transform: translateY(0) scale(1);
    }
}

/* Respect a reduced-motion preference: still fades, but nothing moves. */
@media (prefers-reduced-motion: reduce) {
    .loop-forms-modal.lf-present-centred .lf-container,
    .loop-forms-modal.lf-present-centred.loop-forms-modal--active .lf-container {
        transform: none;
    }
}
