/**
 * LeadFlow v2 — shopper-facing styles.
 *
 * IMPORTANT: this is NOT the Programa admin design system. Everything a shopper
 * sees must adopt the *client's* brand (PRD §11), so this file ships almost no
 * opinions of its own — nearly every declaration reads a `--lf2-*` custom
 * property written by LeadFlow2_Design::to_css_vars(). The values below are
 * fallbacks for a funnel with no theme yet, never the intended look.
 *
 * One static stylesheet serves unlimited brands: the tokens change, this doesn't.
 */

/* ═══════════════════════════════════════════════════════════
   SHELL
   ═══════════════════════════════════════════════════════════ */

.lf2-funnel,
.lf2-funnel *,
.lf2-funnel *::before,
.lf2-funnel *::after { box-sizing: border-box; }

.lf2-funnel {
    font-family: var(--lf2-font, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
    color: var(--lf2-heading-color, #16181d);
    line-height: 1.45;
}

.lf2-funnel[hidden] { display: none !important; }

/**
 * ── No border unless we ask for one ──
 *
 * WordPress's global styles ship this rule:
 *
 *     html :where([style*="border-width"]) { border-style: solid; }
 *
 * It matches on the TEXT of the style attribute, and our shell carries the
 * whole design-token set inline — one of which is literally named
 * `--lf2-option-border-width`. The substring matches, `border-style: solid`
 * switches on, and because no width was ever declared the browser falls back to
 * `medium`: a 2.67px border, in the inherited colour, on all four sides. On
 * Lina's shop and product templates — the pages where WordPress emits that rule
 * — the sticky bar came out framed in white.
 *
 * Declaring zero gives it nothing to draw. Every border this plugin genuinely
 * wants is declared with an explicit width further down, so those are
 * unaffected; this only removes one nobody asked for.
 */
.lf2-funnel,
.lf2-funnel .lf2-panel,
.lf2-funnel .lf2-stage,
.lf2-funnel .lf2-shell { border: 0 solid transparent; }

/**
 * The body face is declared on the panel as well as on the funnel root.
 *
 * `.lf2-funnel` reads `--lf2-font`, and on a live page that works because
 * render_shell() writes the variable onto that same element. The builder canvas
 * builds its own host and writes the variable onto the PANEL, one level down —
 * where the rule above it cannot see it. So the typeface control did nothing in
 * the builder and everything on the storefront, which is the worst way round.
 * Declaring it here covers both, since a value set higher still inherits.
 */
.lf2-panel {
    font-family: var(--lf2-font, inherit);
    background: var(--lf2-canvas-bg, #fff);
    /* Fallback ink for the screen. See --lf2-card-text: the panel painted a
       background and set no colour, so on a dark canvas every element without
       an explicit colour inherited near-black and disappeared. */
    color: var(--lf2-canvas-text, #16181d);
    position: relative;
}

.lf2-stage { position: relative; }

.lf2-shell {
    display: flex;
    align-items: stretch;
    min-height: 100%;
    position: relative;
}

.lf2-col {
    flex: 1 1 auto;
    width: 100%;
    max-width: var(--lf2-canvas-max-width, 720px);
    margin: 0 auto;
    padding: var(--lf2-canvas-padding-y, 48px) 20px;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}

/* Hims and Jones Road anchor their whole column left rather than centering it —
   that single switch changes the character of the funnel more than any color. */
.lf2-panel[data-lf2-align="left"] .lf2-col {
    align-items: flex-start;
    text-align: left;
    margin: 0;
}

.lf2-col > * { width: 100%; }

/* The card panel is opt-in: Juniper sits its content on one, IM8 deliberately
   doesn't. Enabling it is a token, not a different template. */
.lf2-panel:not([data-lf2-card="off"]) .lf2-col {
    background: var(--lf2-card-bg, #fff);
    /* The fallback ink for everything inside the card that does not state its
       own colour — outcome titles, trait chips, tier rows. Without it a dark
       card left them all at the funnel root's near-black. */
    color: var(--lf2-card-text, #16181d);
    border: 1px solid var(--lf2-card-border, #e6e8eb);
    border-radius: var(--lf2-card-radius, 16px);
    padding: var(--lf2-card-padding, 32px);
    margin-top: var(--lf2-canvas-padding-y, 48px);
    margin-bottom: var(--lf2-canvas-padding-y, 48px);
}
.lf2-panel[data-lf2-card="sm"] .lf2-col { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.07); }
.lf2-panel[data-lf2-card="md"] .lf2-col { box-shadow: 0 6px 28px rgba(0, 0, 0, 0.10); }

.lf2-body {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    margin-top: 20px;
}

/* ═══════════════════════════════════════════════════════════
   DISPLAY MODES
   ═══════════════════════════════════════════════════════════ */

.lf2-mode--embed { width: 100%; }

.lf2-mode--fullpage {
    position: fixed;
    inset: 0;
    z-index: 999990;
    overflow-y: auto;
}
.lf2-mode--fullpage .lf2-panel { min-height: 100vh; }

.lf2-funnel--overlay {
    position: fixed;
    z-index: 999990;
}

.lf2-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
}

.lf2-mode--modal { inset: 0; display: flex; align-items: center; justify-content: center; padding: 20px; }
.lf2-mode--modal .lf2-panel {
    position: relative;
    width: 100%;
    max-width: var(--lf2-canvas-max-width, 720px);
    max-height: 90vh;
    overflow-y: auto;
    border-radius: var(--lf2-card-radius, 16px);
}

.lf2-mode--slidein_br,
.lf2-mode--slidein_bl { bottom: 20px; max-width: 420px; width: calc(100% - 40px); }
.lf2-mode--slidein_br { right: 20px; }
.lf2-mode--slidein_bl { left: 20px; }
.lf2-mode--slidein_br .lf2-backdrop,
.lf2-mode--slidein_bl .lf2-backdrop { display: none; } /* A slide-in must not block the page it interrupts. */
.lf2-mode--slidein_br .lf2-panel,
.lf2-mode--slidein_bl .lf2-panel {
    border-radius: var(--lf2-card-radius, 16px);
    box-shadow: 0 8px 40px rgba(0, 0, 0, 0.18);
    overflow: hidden;
}
.lf2-mode--slidein_br .lf2-col,
.lf2-mode--slidein_bl .lf2-col { padding: 28px 24px; }

/* ═══════════════════════════════════════════════════════════
   REWARD LADDER (tiered spend rewards)
   ═══════════════════════════════════════════════════════════ */

.lf2-ladder { width: 100%; margin-bottom: 18px; text-align: center; }

/* Sized as a headline, not as a caption: on the reward-ladder pop-up this line
   IS the headline — the step's own heading is deliberately left empty because
   no fixed sentence is true in all three ladder states. */
.lf2-ladder-head {
    font-size: 19px;
    font-weight: 600;
    line-height: 1.35;
    color: var(--lf2-heading-color, #16181d);
    margin-bottom: 18px;
}
/* Reward names are authored mid-sentence ("₦40,000 more for free delivery"), so
   the same string starts the sentence in the unlocked state and arrives
   lowercase. Capitalising here rather than in the copy means an operator can
   write the reward once, naturally, and have it read correctly in both. */
.lf2-ladder-head::first-letter { text-transform: uppercase; }
.lf2-ladder-head.lf2-is-met { color: var(--lf2-progress-fill, #16181d); }

.lf2-ladder-trackwrap { position: relative; }

.lf2-ladder-track {
    position: relative;
    height: var(--lf2-progress-height, 8px);
    background: var(--lf2-progress-track, #e6e8eb);
    border-radius: var(--lf2-progress-radius, 999px);
    /* Markers sit ON the track and must not be clipped by its radius. */
    overflow: visible;
}
.lf2-ladder-fill {
    height: 100%;
    background: var(--lf2-progress-fill, #16181d);
    border-radius: inherit;
    transition: width 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

/* A rung marker. Centred on its spend position, so the visual distance to the
   next reward is the real distance. */
.lf2-ladder-pip {
    position: absolute;
    top: 50%;
    width: 14px;
    height: 14px;
    margin-left: -7px;
    transform: translateY(-50%);
    background: var(--lf2-progress-track, #e6e8eb);
    border: 2px solid var(--lf2-canvas-bg, #fff);
    border-radius: 999px;
    box-shadow: 0 0 0 1px var(--lf2-progress-track, #e6e8eb);
}
.lf2-ladder-pip.is-met {
    background: var(--lf2-progress-fill, #16181d);
    box-shadow: 0 0 0 1px var(--lf2-progress-fill, #16181d);
}

/* Rung labels, positioned under their markers. The first and last are pulled
   inside the track's ends rather than centred, so neither overhangs the panel. */
.lf2-ladder-rungs { position: relative; height: 34px; margin-top: 10px; }
/* Rungs set so close together that their amounts would overlap drop to a second
   row rather than being hidden — see buildLadderTrack(). */
.lf2-ladder-rungs.lf2-is-staggered { height: 50px; }
.lf2-ladder-rung[data-lf2-row="1"] { top: 18px; }
.lf2-ladder-rung {
    position: absolute;
    top: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
    transform: translateX(-50%);
    white-space: nowrap;
    opacity: 0.55;
}
.lf2-ladder-rung:first-child { transform: none; }
.lf2-ladder-rung:last-child  { transform: translateX(-100%); }
.lf2-ladder-rung.is-met { opacity: 1; }

.lf2-ladder-rung-at {
    font-size: 12px;
    font-weight: 700;
    color: var(--lf2-heading-color, #16181d);
    font-variant-numeric: tabular-nums;
}
.lf2-ladder-rung-reward {
    font-size: 11px;
    color: var(--lf2-subheading-color, #6b7280);
}

/* ── the ladder as a list ──
   The offer stated, rather than progress reported. */
.lf2-tierlist {
    display: flex;
    flex-direction: column;
    gap: 2px;
    text-align: left;
}
.lf2-tierrow {
    display: grid;
    grid-template-columns: 18px auto 16px 1fr;
    align-items: baseline;
    gap: 0 6px;
    padding: 9px 12px;
    border-radius: var(--lf2-option-radius, 8px);
    /* Unearned rungs are quieted, not greyed out — they are targets, and a
       target that looks disabled reads as unavailable. */
    opacity: 0.72;
}
/**
 * A row's ink follows the surface the row is actually painted on.
 *
 * These read `--lf2-progress-fill` and `--lf2-heading-color`, neither of which
 * has anything to do with the box behind them: an earned row is filled with
 * `--lf2-option-selected-bg`. On every dark template that meant near-black text
 * on a dark navy, brown or green fill — between 1.0 and 2.1 contrast, so the
 * unlocked tiers, the exact ones a shopper has earned and most wants to read,
 * were the invisible ones. Keying both states to their own background is what
 * makes the block survive a palette it was not designed against.
 */
/* An unearned row paints no background of its own, so its ink is the card's,
   not the option card's — pinning it to `--lf2-option-text` put white text on a
   white panel for every template with dark answer cards. */
.lf2-tierrow {
    color: inherit;
}
.lf2-tierrow.is-met {
    opacity: 1;
    background: var(--lf2-option-selected-bg, #f6f7f9);
    color: var(--lf2-option-selected-text, #16181d);
}
.lf2-tierrow-mark {
    font-size: 12px;
    font-weight: 700;
    color: inherit;
}
.lf2-tierrow-at {
    font-size: 15px;
    font-weight: 700;
    color: inherit;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
/* The arrow is punctuation between two phrases, so it steps back from both —
   but as a fade of the row's own ink, not as a fixed grey that only works on
   a light card. */
.lf2-tierrow-arrow { color: inherit; opacity: 0.55; }
.lf2-tierrow-reward {
    font-size: 15px;
    font-weight: 600;
    color: inherit;
}

@media (max-width: 420px) {
    .lf2-tierrow { padding: 8px 10px; }
    .lf2-tierrow-at, .lf2-tierrow-reward { font-size: 14px; }
}

/* The arithmetic. Only rendered when the maths genuinely favours the shopper,
   so it is allowed to look like the best thing on the screen. */
.lf2-ladder-maths {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-top: 14px;
    padding: 8px 16px;
    font-size: 14px;
    font-weight: 600;
    border-radius: var(--lf2-button-radius, 12px);
    background: var(--lf2-option-selected-bg, #f6f7f9);
    color: var(--lf2-option-selected-text, #16181d);
    border: 1px dashed currentColor;
}
.lf2-ladder-maths-arrow { opacity: 0.5; }
.lf2-ladder-maths-save { color: inherit; font-weight: 700; }

/* ── gap closers ── */
.lf2-gapitems { margin-top: 20px; }
.lf2-gapitems-label {
    font-size: 12px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--lf2-subheading-color, #6b7280);
    margin-bottom: 10px;
}
.lf2-gapitems-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
}
.lf2-gapitem {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 8px;
    text-align: left;
    text-decoration: none;
    color: var(--lf2-option-text, #16181d);
    background: var(--lf2-option-bg, #fff);
    border: 1px solid var(--lf2-option-border, #d9dce1);
    border-radius: var(--lf2-option-radius, 12px);
}
.lf2-gapitem:hover { border-color: var(--lf2-option-selected-border, #16181d); }
.lf2-gapitem-img {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    border-radius: calc(var(--lf2-option-radius, 12px) - 4px);
}
.lf2-gapitem-name {
    font-size: 13px;
    font-weight: 500;
    color: var(--lf2-option-text, #16181d);
    /* Two lines then ellipsis — wig names are long and a third line pushes the
       price out of the card. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.lf2-gapitem-price { font-size: 13px; font-weight: 700; }
.lf2-gapitem-flag {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--lf2-progress-fill, #16181d);
}

@media (max-width: 560px) {
    .lf2-gapitems-grid { grid-template-columns: repeat(2, 1fr); }
    /* Three rung labels will not fit across a phone, so the reward names drop
       and the amounts — which have to line up with the markers — stay. */
    .lf2-ladder-rung-reward { display: none; }
    .lf2-ladder-rungs { height: 20px; }
    .lf2-ladder-rung-at { font-size: 11px; }
}

/* ── compact: the sticky-bar variant ── */
.lf2-ladder--compact {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 0;
    min-width: 0;
}
.lf2-ladder--compact .lf2-ladder-head {
    margin-bottom: 0;
    font-size: var(--lf2-bar-size, 15px);
    font-weight: var(--lf2-bar-weight, 600);
    color: var(--lf2-bar-text, #fff);
}
.lf2-ladder--compact .lf2-ladder-trackwrap { flex: none; width: 140px; }
.lf2-ladder--compact .lf2-ladder-track {
    height: 6px;
    background: var(--lf2-bar-timer-bg, rgba(255, 255, 255, 0.2));
}
.lf2-ladder--compact .lf2-ladder-fill { background: currentColor; }
.lf2-ladder--compact .lf2-ladder-pip {
    width: 10px;
    height: 10px;
    margin-left: -5px;
    background: var(--lf2-bar-timer-bg, rgba(255, 255, 255, 0.25));
    border-color: transparent;
    box-shadow: none;
}
.lf2-ladder--compact .lf2-ladder-pip.is-met { background: currentColor; }

@media (max-width: 640px) {
    .lf2-ladder--compact { flex-direction: column; gap: 6px; width: 100%; }
    .lf2-ladder--compact .lf2-ladder-trackwrap { width: 100%; }
}

/* ═══════════════════════════════════════════════════════════
   STICKY BAR

   Rebuilt around three rules the reference bars all obey:

     1. The band is full-bleed and its content is too, unless the operator
        explicitly asks for a max width. Site chrome runs edge to edge.
     2. The message carries typographic hierarchy — a bold lead-in and a
        regular remainder — rather than one uniform weight shouting.
     3. The dismiss button is pinned to the edge and is NOT part of the row,
        so a centred message stays optically centred.
   ═══════════════════════════════════════════════════════════ */

.lf2-funnel--bar {
    position: fixed;
    left: 0;
    right: 0;
    /* Above a store's own sticky header, below a modal — a bar that a pop-up
       has to fight for z-order is a bar that will lose on someone's theme. */
    z-index: 99990;
}
.lf2-mode--bar_top    { top: 0; }
.lf2-mode--bar_bottom { bottom: 0; }

/* The builder canvas and the step thumbnails host a real bar, so they need every
   bar rule except the one that pins it to the viewport. */
.lf2-funnel--bar.is-canvas,
.lf2b-thumb-inner.lf2-funnel--bar {
    position: relative;
    inset: auto;
    z-index: auto;
}

/**
 * ── "Push the page down" puts the bar IN THE PAGE, not over it ──
 *
 * This used to stay `position: fixed` and reserve room by putting a padding-top
 * on <html>. Two things go wrong with that, and both showed up on a real store:
 *
 *   1. The reservation and the bar are separate mechanisms that have to agree.
 *      A theme with its own fixed header already reserves space for itself, so
 *      the two reservations stack and leave a band of the html element's own
 *      background — a white stripe above the bar that nothing accounts for.
 *   2. A fixed bar sits over whatever is beneath it. Any theme whose header is
 *      also pinned loses that fight, and the store's logo disappears under the
 *      announcement.
 *
 * A bar in normal flow cannot do either. It IS the top of the page, so nothing
 * can be double-reserved and nothing can be covered — and it needs no measuring,
 * so there is no number to get wrong. `sticky` then keeps it on screen while
 * scrolling without taking it back out of the flow.
 */
.lf2-mode--bar_top[data-lf2-bar-flow="on"] {
    position: static;
    z-index: 99990;
}
.lf2-mode--bar_top[data-lf2-bar-flow="on"][data-lf2-bar-sticky="on"] {
    position: sticky;
    top: 0;
}

/* "Stay put" off on a FLOATING bar means it scrolls away with the page it
   introduced. Only meaningful at the top — a bottom bar that scrolls away is
   just a footer. */
.lf2-mode--bar_top[data-lf2-bar-sticky="off"]:not([data-lf2-bar-flow="on"]) { position: absolute; }

.lf2-funnel--bar .lf2-panel {
    background: var(--lf2-bar-fill, #16181d);
    color: var(--lf2-bar-text, #fff);
    border-radius: var(--lf2-bar-radius, 0);
    padding: var(--lf2-bar-padding-y, 13px) var(--lf2-bar-padding-x, 28px);
    /* The border only reads as an edge on the side facing the page. */
    border-bottom: 1px solid var(--lf2-bar-border, transparent);
}
.lf2-mode--bar_bottom .lf2-panel {
    border-bottom: 0;
    border-top: 1px solid var(--lf2-bar-border, transparent);
}

.lf2-funnel--bar .lf2-panel[data-lf2-bar-shadow="sm"] { box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12); }
.lf2-funnel--bar .lf2-panel[data-lf2-bar-shadow="md"] { box-shadow: 0 4px 20px rgba(0, 0, 0, 0.18); }

/* A radius above zero turns the band into a floating pill, which only makes
   sense if it is also pulled in from the viewport edges. One token, one look. */
.lf2-funnel--bar .lf2-panel[data-lf2-bar-pill="on"] {
    margin: var(--lf2-bar-inset, 0) auto;
    max-width: calc(100% - (var(--lf2-bar-inset, 0px) * 2));
    width: var(--lf2-bar-max-width, none);
    border: 1px solid var(--lf2-bar-border, transparent);
}

.lf2-funnel--bar .lf2-stage {
    position: relative;
    display: flex;
    align-items: center;
    width: 100%;
    max-width: var(--lf2-bar-max-width, none);
    margin: 0 auto;
}

.lf2-bar {
    display: flex;
    flex: 1 1 auto;
    flex-wrap: wrap;
    align-items: center;
    justify-content: var(--lf2-bar-justify, center);
    gap: var(--lf2-bar-gap, 22px);
    min-width: 0;
}
/* Room for the pinned dismiss button so a right-aligned action never slides
   underneath it. Reserved on both sides when the row is centred, so the
   centring stays true. */
.lf2-panel[data-lf2-bar-close="on"] .lf2-bar { padding-right: 34px; }
.lf2-panel[data-lf2-bar-close="on"][data-lf2-bar-align="center"] .lf2-bar { padding-left: 34px; }

/* The message group. Baseline-aligned so the bold lead-in and the regular
   remainder sit on one line like a sentence, rather than being centred against
   each other like two separate objects. */
.lf2-bar-main {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0 7px;
    min-width: 0;
}
/**
 * The action group wraps too.
 *
 * A countdown and a coupon chip are both `flex: none` — they have to be, or the
 * clock reflows every second and the code truncates — so on a narrow screen the
 * pair simply pushed past the viewport edge and took the page's horizontal
 * scrollbar with them. Letting the group wrap moves the chip under the clock
 * instead, which is the only way a bar carrying three pieces fits a 375px phone.
 */
.lf2-bar-actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    justify-content: center;
    gap: 12px;
    min-width: 0;
}

.lf2-bar-icon { font-size: 1.1em; line-height: 1; flex: none; align-self: center; }

.lf2-bar-eyebrow {
    font-size: var(--lf2-bar-size, 14px);
    font-weight: var(--lf2-bar-eyebrow-weight, 700);
    color: var(--lf2-bar-eyebrow-color, var(--lf2-bar-text, #fff));
    letter-spacing: 0.02em;
    white-space: nowrap;
}

.lf2-bar-message {
    font-size: var(--lf2-bar-size, 14px);
    font-weight: var(--lf2-bar-weight, 400);
    color: var(--lf2-bar-text, #fff);
    /* Wraps rather than truncating. A cut-off announcement is worse than a
       two-line one, and the offset measurement in JS handles the extra height. */
    min-width: 0;
    opacity: 0.92;
}

/* ── marquee ──
   Two identical copies in a track that travels exactly one copy's width, so the
   reset frame is indistinguishable from any other frame. */
.lf2-marquee {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    /* Fades the content into the band's own colour at both ends, so text
       appears from and disappears into the bar rather than being guillotined by
       a hard edge. */
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent);
            mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent);
}
.lf2-marquee-track {
    display: flex;
    width: max-content;
    animation: lf2-marquee var(--lf2-bar-marquee-speed, 40s) linear infinite;
}
.lf2-marquee-item {
    flex: none;
    /* The gap belongs to the item, not the track: `gap` on the track would sit
       between the two copies but not after the second, so the loop would stutter
       by exactly one gap on every lap. */
    padding-right: var(--lf2-bar-marquee-gap, 64px);
}
/* Pausing on hover is what makes a moving bar usable — you cannot click a
   button that is sliding away from the pointer. */
.lf2-marquee:hover .lf2-marquee-track,
.lf2-marquee:focus-within .lf2-marquee-track { animation-play-state: paused; }

@keyframes lf2-marquee {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}

/* Reduced motion, or an explicit off: no track animation, no duplicate. */
.lf2-marquee[data-lf2-marquee="off"] { -webkit-mask-image: none; mask-image: none; }
.lf2-marquee[data-lf2-marquee="off"] .lf2-marquee-track { animation: none; width: 100%; }

@media (prefers-reduced-motion: reduce) {
    .lf2-marquee-track { animation: none; }
}

/* ── the bar's own dismiss ──
   Absolutely positioned, so it never takes width from the row. */
.lf2-bar-close {
    position: absolute;
    top: 50%;
    right: 0;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    font-size: 17px;
    line-height: 1;
    color: var(--lf2-bar-close-color, #fff);
    background: none;
    border: 0;
    border-radius: 999px;
    cursor: pointer;
    opacity: 0.6;
    transition: opacity 0.15s ease, background 0.15s ease;
}
.lf2-bar-close:hover { opacity: 1; }
/* The circle variant reads as a control rather than as a stray glyph, which is
   what a bare × on a saturated band looks like. */
.lf2-panel[data-lf2-bar-x="circle"] .lf2-bar-close {
    background: rgba(127, 127, 127, 0.22);
    font-size: 15px;
}
.lf2-panel[data-lf2-bar-x="circle"] .lf2-bar-close:hover { background: rgba(127, 127, 127, 0.38); }

/* ── countdown ── */
.lf2-bar-timer {
    display: flex;
    align-items: baseline;
    gap: 7px;
    flex: none;
    padding: 5px 11px;
    background: var(--lf2-bar-timer-bg, rgba(255, 255, 255, 0.14));
    border-radius: 6px;
    color: var(--lf2-bar-timer-text, #fff);
}
.lf2-bar-timer-label { font-size: 0.82em; opacity: 0.8; white-space: nowrap; }
.lf2-bar-timer-face {
    /* Tabular figures so the seconds column does not jitter the whole row
       sideways once a second — the single most distracting thing a bar can do. */
    font-variant-numeric: tabular-nums;
    font-feature-settings: 'tnum';
    font-weight: 700;
    white-space: nowrap;
}

/* ── coupon chip ── */
.lf2-bar-code {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0;
    flex: none;
    padding: 4px 13px;
    font: inherit;
    color: var(--lf2-bar-code-text, #fff);
    background: var(--lf2-bar-code-bg, rgba(255, 255, 255, 0.14));
    border: 1px dashed currentColor;
    border-radius: 6px;
    cursor: pointer;
}
.lf2-bar-code-value { font-weight: 700; letter-spacing: 0.08em; font-size: 0.95em; }
.lf2-bar-code-hint { font-size: 9px; text-transform: uppercase; letter-spacing: 0.07em; opacity: 0.7; }
.lf2-bar-code.lf2-is-copied { border-style: solid; }

/* ── inline form ── */
.lf2-bar-form { display: flex; gap: 8px; flex: 1 1 280px; min-width: 0; max-width: 420px; }
.lf2-bar-input {
    flex: 1 1 auto;
    min-width: 0;
    padding: 9px 13px;
    font: inherit;
    font-size: 14px;
    color: var(--lf2-input-text, #16181d);
    background: var(--lf2-input-bg, #fff);
    border: 1px solid var(--lf2-input-border, #d9dce1);
    border-radius: var(--lf2-input-radius, 6px);
}
.lf2-bar-input[aria-invalid="true"] { border-color: #b3261e; }
.lf2-bar-success { font-weight: 600; color: var(--lf2-bar-text, #fff); }

/* ── the button ──
   Outlined by default. A solid white block on a saturated band out-shouts the
   sentence it is meant to support; a border says "this is clickable" without
   competing for the eye. */
.lf2-bar-btn {
    flex: none;
    width: auto;
    padding: 7px 16px;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.02em;
    white-space: nowrap;
    text-decoration: none;
    border-radius: var(--lf2-button-radius, 6px);
    transition: background 0.15s ease, color 0.15s ease;
}
.lf2-panel[data-lf2-bar-btn="outline"] .lf2-bar-btn {
    background: transparent;
    color: var(--lf2-bar-text, #fff);
    border: 1px solid currentColor;
}
.lf2-panel[data-lf2-bar-btn="outline"] .lf2-bar-btn:hover {
    background: var(--lf2-bar-text, #fff);
    color: var(--lf2-bar-fill, #16181d);
}
.lf2-panel[data-lf2-bar-btn="solid"] .lf2-bar-btn {
    background: var(--lf2-button-bg, #16181d);
    color: var(--lf2-button-text, #fff);
    border: 1px solid transparent;
}
/* The submit button on an inline form is always solid — an outlined button
   beside a filled input reads as the secondary of the two, which is backwards. */
.lf2-bar-form .lf2-bar-btn {
    background: var(--lf2-button-bg, #16181d);
    color: var(--lf2-button-text, #fff);
    border: 1px solid transparent;
}

/* ── free shipping progress ── */
.lf2-bar-threshold { display: flex; align-items: center; gap: 12px; min-width: 0; }
.lf2-bar-threshold-label {
    font-size: var(--lf2-bar-size, 14px);
    font-weight: var(--lf2-bar-weight, 400);
    color: var(--lf2-bar-text, #fff);
}
.lf2-bar-threshold-track {
    display: block;
    flex: none;
    width: 130px;
    height: 5px;
    background: var(--lf2-bar-timer-bg, rgba(255, 255, 255, 0.2));
    border-radius: 999px;
    overflow: hidden;
}
.lf2-bar-threshold-fill {
    display: block;
    height: 100%;
    background: currentColor;
    border-radius: 999px;
    transition: width 0.3s ease;
}

/* ── reserving room for the bar ──
   The offset is measured in JS (it depends on padding, font size and whether
   the row wrapped) and spent here. scroll-padding matters as much as the
   padding itself: without it every #anchor on the store lands with its heading
   hidden underneath the bar. */
.lf2-has-bar-top {
    padding-top: var(--lf2-bar-offset-top, 0);
    scroll-padding-top: var(--lf2-bar-offset-top, 0);
}
.lf2-has-bar-bottom {
    padding-bottom: var(--lf2-bar-offset-bottom, 0);
    scroll-padding-bottom: var(--lf2-bar-offset-bottom, 0);
}

/* ── tablets and below ──
   The split layout is the first thing to go: message-left / button-right needs
   real width, and below this it just pushes both into the middle awkwardly. */
@media (max-width: 860px) {
    .lf2-panel[data-lf2-bar-align="between"] .lf2-bar { justify-content: center; }
}

/* ── phones ──
   Below this width the row cannot hold message and actions side by side without
   shrinking the type past readable, so it stacks: message on the first line,
   actions on the second, × pinned to the top corner of both. */
@media (max-width: 640px) {
    .lf2-funnel--bar .lf2-panel {
        padding-left: 16px;
        padding-right: 16px;
    }
    .lf2-panel[data-lf2-bar-stack="on"] .lf2-bar {
        flex-direction: column;
        align-items: stretch;
        justify-content: flex-start;
        text-align: center;
        gap: 9px;
        /* The × moves to the top corner on mobile, so the row no longer needs
           to reserve horizontal room for it. */
        padding-right: 0;
        padding-left: 0;
    }
    .lf2-panel[data-lf2-bar-stack="on"] .lf2-bar-main,
    .lf2-panel[data-lf2-bar-stack="on"] .lf2-bar-actions {
        justify-content: center;
        flex-wrap: wrap;
    }

    /**
     * A marquee row is a ticker, and stays one on a phone.
     *
     * "Wrap onto two lines on phones" above sets `padding-right: 0` and stacks
     * the row into a column — both correct for a static bar and both wrong for
     * a scrolling one. The zeroed padding IS the gap between repeats, so on
     * mobile the copies ran straight into each other with no space at all, and
     * the column direction would stack a ticker vertically. Higher specificity
     * than the stack rule, and after it, so it wins on both counts.
     */
    .lf2-panel[data-lf2-bar-stack="on"] .lf2-bar.lf2-marquee-item {
        flex-direction: row;
        align-items: center;
        justify-content: flex-start;
        flex-wrap: nowrap;
        width: auto;
        gap: var(--lf2-bar-gap, 22px);
        padding-left: 0;
        padding-right: var(--lf2-bar-marquee-gap, 64px);
    }
    /* The pieces inside must not wrap either — a ticker is one line by
       definition, and a wrapped copy is a different width from its duplicate,
       which is what makes a loop visibly stutter. */
    .lf2-panel[data-lf2-bar-stack="on"] .lf2-marquee-item .lf2-bar-main,
    .lf2-panel[data-lf2-bar-stack="on"] .lf2-marquee-item .lf2-bar-actions {
        flex-wrap: nowrap;
        white-space: nowrap;
    }
    /* The marquee reserves no room for the × — the dismiss button is pinned
       outside the scrolling track, not carried along inside it. */
    .lf2-funnel--bar .lf2-marquee { padding-right: 0; }
    .lf2-funnel--bar .lf2-bar-close {
        top: 2px;
        right: 0;
        transform: none;
    }
    .lf2-funnel--bar .lf2-stage { padding-right: 22px; }
    .lf2-bar-threshold { flex-direction: column; gap: 5px; width: 100%; }
    .lf2-bar-threshold-track { width: 100%; }
    .lf2-bar-form { flex: 1 1 100%; max-width: none; }
    .lf2-bar-btn { padding: 9px 18px; }
}


.lf2-mode--topbar { top: 0; left: 0; right: 0; }
.lf2-mode--topbar .lf2-backdrop { display: none; }
.lf2-mode--topbar .lf2-panel { border-bottom: 1px solid var(--lf2-card-border, #e6e8eb); }
.lf2-mode--topbar .lf2-col { padding: 14px 20px; max-width: none; }
.lf2-mode--topbar .lf2-body { margin-top: 8px; }

body.lf2-scroll-lock { overflow: hidden; }

.lf2-close {
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 2;
    width: 32px;
    height: 32px;
    border: 0;
    background: transparent;
    font-size: 26px;
    line-height: 1;
    cursor: pointer;
    color: var(--lf2-heading-color, #16181d);
}

/* ═══════════════════════════════════════════════════════════
   MEDIA
   ═══════════════════════════════════════════════════════════ */

.lf2-media { overflow: hidden; }
.lf2-media img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Stated rather than left to the initial value, because it is the whole
       point: whatever shape the operator uploads, the middle of the picture is
       what survives the crop. A portrait wig shot and a landscape one both keep
       the face. */
    object-position: center center;
}

.lf2-panel[data-lf2-media="split"] .lf2-media,
.lf2-panel[data-lf2-media="left"] .lf2-media,
.lf2-panel[data-lf2-media="right"] .lf2-media {
    flex: 0 0 var(--lf2-layout-media-width, 50%);
}

.lf2-panel[data-lf2-media="top"] .lf2-media {
    border-radius: var(--lf2-layout-media-radius, 12px);
    margin-bottom: 20px;
    max-height: 260px;
}

.lf2-media--bg {
    position: absolute;
    inset: 0;
    z-index: 0;
}
.lf2-panel[data-lf2-media="background"] .lf2-col { position: relative; z-index: 1; }

@media (max-width: 640px) {
    /* A half-and-half split becomes unreadable on a phone; stack it. */
    .lf2-shell { flex-direction: column; }

    /**
     * A DEFINITE height, not a max-height.
     *
     * `max-height` on a box whose height is auto never gives the image a box to
     * cover: `height: 100%` resolves to auto, the picture renders at its own
     * aspect ratio, and the max-height then simply clips whatever hangs below.
     * On a tall portrait photo that means the crop keeps the TOP — a wig shot
     * came out as a band of the background above the model's head, with the
     * face cut off. Side by side on desktop the column is stretched by the flex
     * row, so it has always worked there and only the stacked phone layout was
     * wrong.
     *
     * Sized against the viewport so the picture and the offer share the screen
     * rather than the picture pushing the offer off the bottom of it.
     */
    .lf2-panel[data-lf2-media="split"] .lf2-media,
    .lf2-panel[data-lf2-media="left"] .lf2-media,
    .lf2-panel[data-lf2-media="right"] .lf2-media,
    .lf2-panel[data-lf2-media="top"] .lf2-media {
        flex: 0 0 auto;
        height: 26vh;
        min-height: 140px;
        max-height: 240px;
    }
}

/* ═══════════════════════════════════════════════════════════
   TOP BAR
   ═══════════════════════════════════════════════════════════ */

.lf2-topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
    margin-bottom: 12px;
}
.lf2-topbar-back,
.lf2-topbar-close {
    border: 0;
    background: transparent;
    font-size: 24px;
    line-height: 1;
    cursor: pointer;
    padding: 0 4px;
    color: var(--lf2-heading-color, #16181d);
}
.lf2-topbar-back.lf2-is-invisible { visibility: hidden; }
.lf2-topbar-label {
    font-size: var(--lf2-progress-counter-size, 13px);
    color: var(--lf2-progress-counter-color, #6b7280);
}
.lf2-topbar-spacer { width: 24px; }

/* ═══════════════════════════════════════════════════════════
   PROGRESS
   ═══════════════════════════════════════════════════════════ */

.lf2-progress { width: var(--lf2-progress-width, 100%); margin-bottom: 20px; }

.lf2-progress-counter {
    font-size: var(--lf2-progress-counter-size, 13px);
    color: var(--lf2-progress-counter-color, #6b7280);
    font-weight: 700;
    letter-spacing: 0.04em;
    margin-bottom: 6px;
    text-align: left;
}

.lf2-track {
    width: 100%;
    height: var(--lf2-progress-height, 6px);
    background: var(--lf2-progress-track, #e6e8eb);
    border-radius: var(--lf2-progress-radius, 999px);
    overflow: hidden;
}
.lf2-fill {
    height: 100%;
    background: var(--lf2-progress-fill, #16181d);
    border-radius: inherit;
    transition: width 0.25s ease;
}

.lf2-segs { display: flex; gap: 4px; }
.lf2-seg {
    flex: 1;
    height: var(--lf2-progress-height, 6px);
    background: var(--lf2-progress-track, #e6e8eb);
    border-radius: var(--lf2-progress-radius, 999px);
}
.lf2-seg.lf2-is-done { background: var(--lf2-progress-fill, #16181d); }

.lf2-dots-row { display: flex; align-items: center; gap: 8px; }
.lf2-dots-row .lf2-track { flex: 1; }
.lf2-dots { display: flex; gap: 6px; }
.lf2-dot {
    width: var(--lf2-progress-height, 6px);
    height: var(--lf2-progress-height, 6px);
    border-radius: 50%;
    background: var(--lf2-progress-track, #e6e8eb);
}

/* IM8's named phases: three coarse blocks read as "almost done" in a way a
   per-question bar never does. */
.lf2-phases { display: flex; gap: 6px; }
.lf2-phase { flex: 1; }
.lf2-phase-lane {
    height: var(--lf2-progress-height, 6px);
    background: var(--lf2-progress-track, #e6e8eb);
    border-radius: var(--lf2-progress-radius, 999px);
    overflow: hidden;
}
.lf2-phase-fill { height: 100%; width: 0; background: var(--lf2-progress-fill, #16181d); border-radius: inherit; }
.lf2-phase.lf2-is-done .lf2-phase-fill { width: 100%; }
.lf2-phase.lf2-is-active .lf2-phase-fill { width: 50%; }
.lf2-phase-label {
    margin-top: 6px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-align: center;
    color: var(--lf2-progress-counter-color, #6b7280);
}
.lf2-phase.lf2-is-active .lf2-phase-label { color: var(--lf2-heading-color, #16181d); }
.lf2-phase.lf2-is-done .lf2-phase-label { color: var(--lf2-progress-fill, #16181d); }

/* ═══════════════════════════════════════════════════════════
   TYPE
   ═══════════════════════════════════════════════════════════ */

.lf2-logobar {
    display: flex;
    justify-content: var(--lf2-header-justify, center);
    align-items: center;
    margin-bottom: 20px;
    padding: 10px 0;
    background: var(--lf2-header-bg, transparent);
    border-bottom: 1px solid var(--lf2-header-border, transparent);
}
.lf2-logo { width: var(--lf2-header-logo-width, 120px); height: auto; display: block; }

.lf2-badge {
    display: inline-block;
    width: auto !important;
    align-self: inherit;
    padding: 5px 12px;
    margin-bottom: 14px;
    background: var(--lf2-badge-bg, #f3f4f6);
    color: var(--lf2-badge-color, #16181d);
    font-size: var(--lf2-badge-size, 12px);
    font-weight: var(--lf2-badge-weight, 700);
    border-radius: var(--lf2-badge-radius, 999px);
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

/**
 * The headline face.
 *
 * Falls through to the body face, which falls through to the system stack — so
 * a funnel that sets one typeface, or none, is unaffected by this existing. The
 * list below is everything that reads as a headline rather than as prose: the
 * step heading, the outcome and score titles, the score figure itself, and the
 * reward ladder's own line, which IS the headline on the announcement pop-up
 * because the step's heading is deliberately left empty there.
 */
.lf2-heading,
.lf2-outcome-title,
.lf2-score-title,
.lf2-score-value,
.lf2-locked-score,
.lf2-ladder-head,
.lf2-bar-eyebrow {
    font-family: var(--lf2-font-heading, var(--lf2-font, inherit));
}

.lf2-heading {
    margin: 0 0 10px;
    color: var(--lf2-heading-color, #16181d);
    font-size: var(--lf2-heading-size, 32px);
    font-weight: var(--lf2-heading-weight, 700);
    text-align: var(--lf2-heading-align, center);
    text-transform: var(--lf2-heading-transform, none);
    letter-spacing: var(--lf2-heading-spacing, 0);
    line-height: 1.2;
}

.lf2-sub {
    margin: 0;
    color: var(--lf2-subheading-color, #6b7280);
    font-size: var(--lf2-subheading-size, 16px);
    font-weight: var(--lf2-subheading-weight, 400);
    text-align: var(--lf2-subheading-align, center);
}

.lf2-footnote {
    margin-top: 16px;
    color: var(--lf2-footnote-color, #9ca3af);
    font-size: var(--lf2-footnote-size, 13px);
    text-align: center;
}

.lf2-callout {
    padding: 16px 20px;
    background: var(--lf2-badge-bg, #f3f4f6);
    color: var(--lf2-heading-color, #16181d);
    border-radius: var(--lf2-card-radius, 12px);
    font-weight: 600;
}

.lf2-stats { display: flex; gap: 20px; justify-content: center; flex-wrap: wrap; }
.lf2-stat { text-align: center; }
.lf2-stat-value { font-size: 22px; font-weight: 700; color: var(--lf2-heading-color, #16181d); }
.lf2-stat-label { font-size: 12px; color: var(--lf2-subheading-color, #6b7280); }

.lf2-roadmap { margin: 0; padding-left: 20px; text-align: left; }
.lf2-roadmap-item { margin-bottom: 8px; color: var(--lf2-subheading-color, #6b7280); }

.lf2-recap {
    border: 1px solid var(--lf2-card-border, #e6e8eb);
    border-radius: var(--lf2-card-radius, 12px);
    padding: 8px 16px;
    text-align: left;
}
.lf2-recap-row {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    padding: 8px 0;
    border-bottom: 1px solid var(--lf2-card-border, #e6e8eb);
    font-size: 14px;
}
.lf2-recap-row:last-child { border-bottom: 0; }
.lf2-recap-q { color: var(--lf2-subheading-color, #6b7280); }
.lf2-recap-a { font-weight: 600; }

/* ═══════════════════════════════════════════════════════════
   OPTIONS
   ═══════════════════════════════════════════════════════════ */

.lf2-options { display: flex; flex-direction: column; gap: var(--lf2-layout-gap, 12px); }

.lf2-options--grid,
.lf2-options--cards,
.lf2-options--image_grid,
.lf2-options--swatch {
    display: grid;
    /* Read straight from the theme token — the column count had been set by a
       separate inline property, which meant the token itself was inert. */
    grid-template-columns: repeat(var(--lf2-option-columns, 2), minmax(0, 1fr));
}

.lf2-opt {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: var(--lf2-option-padding-y, 16px) var(--lf2-option-padding-x, 16px);
    background: var(--lf2-option-bg, #fff);
    border: var(--lf2-option-border-width, 1px) solid var(--lf2-option-border, #d9dce1);
    border-radius: var(--lf2-option-radius, 12px);
    color: var(--lf2-option-text, #16181d);
    font-family: inherit;
    font-size: var(--lf2-option-size, 16px);
    font-weight: var(--lf2-option-weight, 500);
    text-align: var(--lf2-option-align, left);
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease;
}
.lf2-opt:hover { border-color: var(--lf2-option-selected-border, #16181d); }
.lf2-opt.lf2-is-selected {
    background: var(--lf2-option-selected-bg, #f6f7f9);
    border-color: var(--lf2-option-selected-border, #16181d);
    color: var(--lf2-option-selected-text, #16181d);
}

.lf2-opt-text { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.lf2-opt-label { line-height: 1.3; }
.lf2-opt-sub {
    font-size: 13px;
    font-weight: 400;
    color: var(--lf2-option-subtext, #6b7280);
}
.lf2-opt-emoji { flex: 0 0 auto; font-size: 20px; line-height: 1; }

/* Fabletics puts the label left and a swatch block right; Jones Road shows the
   image alone with no label at all. Both are option layouts, not new code. */
.lf2-options--cards .lf2-opt,
.lf2-options--image_grid .lf2-opt { flex-direction: column; align-items: stretch; padding: 0; overflow: hidden; }
.lf2-options--cards .lf2-opt-text,
.lf2-options--image_grid .lf2-opt-text { padding: 12px 14px; }
.lf2-options--image_grid .lf2-opt-text:empty { display: none; }

.lf2-opt-img { display: block; width: 100%; height: auto; object-fit: cover; }
.lf2-options--list .lf2-opt-img { width: 56px; height: 56px; border-radius: 8px; }
.lf2-options--swatch .lf2-opt { flex-direction: row; padding: 0; }
.lf2-options--swatch .lf2-opt-text { padding: 16px; }
.lf2-options--swatch .lf2-opt-img { width: 40%; height: 100%; }

.lf2-marker {
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    border: 1px solid var(--lf2-option-border, #d9dce1);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    font-weight: 700;
}
.lf2-marker--radio { border-radius: 50%; }
.lf2-marker--check { border-radius: 5px; }
.lf2-marker--rank { border-radius: 50%; }
.lf2-is-selected .lf2-marker {
    border-color: var(--lf2-option-selected-border, #16181d);
    background: var(--lf2-option-selected-border, #16181d);
    color: var(--lf2-option-bg, #fff);
}
.lf2-is-selected .lf2-marker--check::after { content: '✓'; }
.lf2-is-selected .lf2-marker--radio { box-shadow: inset 0 0 0 3px var(--lf2-option-bg, #fff); }

.lf2-select-counter {
    font-size: 13px;
    color: var(--lf2-subheading-color, #6b7280);
    text-align: center;
}

/* ═══════════════════════════════════════════════════════════
   BUTTONS & INPUTS
   ═══════════════════════════════════════════════════════════ */

.lf2-btn {
    display: inline-block;
    align-self: center;
    padding: var(--lf2-button-padding-y, 14px) var(--lf2-button-padding-x, 28px);
    background: var(--lf2-button-bg, #16181d);
    color: var(--lf2-button-text, #fff);
    border: 1px solid var(--lf2-button-border, transparent);
    border-radius: var(--lf2-button-radius, 12px);
    font-family: inherit;
    font-size: var(--lf2-button-size, 16px);
    font-weight: var(--lf2-button-weight, 600);
    text-transform: var(--lf2-button-transform, none);
    letter-spacing: 0.02em;
    text-decoration: none;
    text-align: center;
    cursor: pointer;
    margin-top: 8px;
}
.lf2-btn:disabled {
    background: var(--lf2-button-disabled-bg, #d1d5db);
    color: var(--lf2-button-disabled-text, #fff);
    cursor: not-allowed;
}
/* Full-width is a token, so IM8's edge-to-edge pill and Juniper's inline
   button are the same element with a different theme. */
.lf2-btn { width: var(--lf2-button-width, auto); }

.lf2-skip,
.lf2-back {
    align-self: center;
    background: none;
    border: 0;
    padding: 6px;
    font-family: inherit;
    font-size: 14px;
    color: var(--lf2-subheading-color, #6b7280);
    text-decoration: underline;
    cursor: pointer;
}

.lf2-form { display: flex; flex-direction: column; gap: 10px; }

.lf2-input,
.lf2-select {
    width: 100%;
    padding: var(--lf2-input-padding-y, 14px) 16px;
    background: var(--lf2-input-bg, #fff);
    border: 1px solid var(--lf2-input-border, #d9dce1);
    border-radius: var(--lf2-input-radius, 12px);
    color: var(--lf2-input-text, #16181d);
    font-family: inherit;
    font-size: var(--lf2-input-size, 16px);
}
.lf2-input::placeholder { color: var(--lf2-input-placeholder, #9ca3af); }
.lf2-input.lf2-has-error { border-color: #b3261e; }

.lf2-consent {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    font-size: 12px;
    color: var(--lf2-footnote-color, #9ca3af);
    text-align: left;
}

.lf2-error { color: #b3261e; font-size: 14px; min-height: 0; }
.lf2-error:empty { display: none; }

.lf2-slider { width: 100%; accent-color: var(--lf2-progress-fill, #16181d); }
.lf2-slider-value { font-size: 32px; font-weight: 700; text-align: center; }
.lf2-slider-labels {
    display: flex;
    justify-content: space-between;
    font-size: 13px;
    color: var(--lf2-subheading-color, #6b7280);
}

/* ═══════════════════════════════════════════════════════════
   LOCKED SCORE (the curiosity-gap gate)
   ═══════════════════════════════════════════════════════════ */

.lf2-locked {
    position: relative;
    padding: 24px;
    border: 1px solid var(--lf2-card-border, #e6e8eb);
    border-radius: var(--lf2-card-radius, 16px);
    background: var(--lf2-card-bg, #fff);
    /* This panel paints the card colour on a screen whose canvas may be a
       completely different shade, so it has to restate the card's ink or it
       inherits the canvas's and lands white-on-white. */
    color: var(--lf2-card-text, #16181d);
    overflow: hidden;
}
/* Size and weight already make this the loudest thing on the panel; taking a
   colour from the progress track as well put pale cream on a white card. */
.lf2-locked-score {
    font-size: 44px;
    font-weight: 800;
    line-height: 1;
    color: inherit;
    text-align: center;
}
.lf2-locked-label {
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: inherit;
    opacity: 0.7;
    text-align: center;
    margin-bottom: 16px;
}
.lf2-locked-bars { display: flex; flex-direction: column; gap: 10px; filter: blur(4px); }
.lf2-locked-bar { display: flex; align-items: center; gap: 12px; font-size: 13px; }
.lf2-locked-bar-label { flex: 0 0 90px; text-align: left; }
.lf2-locked-bar-track {
    flex: 1;
    height: 8px;
    background: var(--lf2-progress-track, #e6e8eb);
    border-radius: 999px;
    overflow: hidden;
}
.lf2-locked-bar-fill { display: block; height: 100%; background: var(--lf2-progress-fill, #16181d); }
.lf2-locked-veil {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 24px;
    text-align: center;
    font-size: 22px;
}

/* ═══════════════════════════════════════════════════════════
   RESULTS
   ═══════════════════════════════════════════════════════════ */

.lf2-outcome, .lf2-score { text-align: center; }
.lf2-outcome-img { max-width: 220px; height: auto; margin: 0 auto 16px; display: block; border-radius: var(--lf2-card-radius, 16px); }
.lf2-outcome-eyebrow {
    font-size: 12px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--lf2-badge-color, #16181d);
}
.lf2-outcome-title, .lf2-score-title {
    margin: 6px 0 8px;
    font-size: calc(var(--lf2-heading-size, 32px) * 0.75);
    font-weight: var(--lf2-heading-weight, 700);
}
.lf2-outcome-desc, .lf2-score-desc { color: var(--lf2-subheading-color, #6b7280); margin: 0; }
.lf2-outcome-traits { list-style: none; padding: 0; margin: 14px 0 0; display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.lf2-outcome-traits li {
    padding: 5px 12px;
    background: var(--lf2-badge-bg, #f3f4f6);
    border-radius: 999px;
    font-size: 13px;
}

/* `--lf2-progress-fill` is a colour chosen to read as a filled TRACK, not as
   text — on the dark Lina theme it is a pale cream that scored 1.8 against the
   white results card. The score is a headline-sized number, so it takes the
   headline's colour, which every template does set deliberately. */
.lf2-score-value { font-size: 52px; font-weight: 800; line-height: 1; color: var(--lf2-heading-color, #16181d); }
.lf2-score-label { font-size: 13px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--lf2-subheading-color, #6b7280); }

.lf2-products {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 16px;
    margin-top: 20px;
}
.lf2-product {
    display: block;
    padding: 12px;
    border: 1px solid var(--lf2-card-border, #e6e8eb);
    border-radius: var(--lf2-card-radius, 16px);
    background: var(--lf2-card-bg, #fff);
    color: var(--lf2-card-text, #16181d);
    text-decoration: none;
    text-align: left;
}
.lf2-product-img { width: 100%; height: auto; border-radius: 10px; display: block; margin-bottom: 10px; }
.lf2-product-name { font-weight: 600; font-size: 15px; }
.lf2-product-price { font-size: 14px; color: var(--lf2-subheading-color, #6b7280); }
.lf2-product-desc { font-size: 13px; color: var(--lf2-subheading-color, #6b7280); margin-top: 6px; }
.lf2-empty { grid-column: 1 / -1; color: var(--lf2-subheading-color, #6b7280); text-align: center; }

/* ═══════════════════════════════════════════════════════════
   LOADING
   ═══════════════════════════════════════════════════════════ */

.lf2-loading { display: flex; justify-content: center; padding: 48px 0; width: 100%; }
.lf2-spinner {
    width: 24px;
    height: 24px;
    border: 2px solid var(--lf2-progress-track, #e6e8eb);
    border-top-color: var(--lf2-progress-fill, #16181d);
    border-radius: 50%;
    animation: lf2-spin 0.7s linear infinite;
}
@keyframes lf2-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
    .lf2-spinner { animation-duration: 2s; }
    .lf2-fill { transition: none; }
}

@media (max-width: 560px) {
    .lf2-col { padding: 28px 18px; }
    .lf2-heading { font-size: calc(var(--lf2-heading-size, 32px) * 0.8); }
    .lf2-options--grid,
    .lf2-options--cards,
    .lf2-options--swatch { grid-template-columns: 1fr; }

    /**
     * A pop-up should fit the phone, not become a page you scroll.
     *
     * A stacked image-plus-offer modal ran past the viewport and turned into a
     * scrolling column, which buries the button — the one thing it exists to
     * get pressed — below the fold of a thing that is already an interruption.
     * Tightening the column here, with the picture capped against the viewport
     * above, is what makes the whole offer land on one screen.
     *
     * `overflow-y: auto` deliberately stays on the panel. It is a safety valve,
     * not the layout: on a very short screen, or with copy far longer than
     * these blueprints ship with, something has to give, and content the
     * shopper cannot reach at all is a worse failure than a scrollbar.
     */
    /**
     * Use the screen rather than shrink the content.
     *
     * The panel was capped at 90vh with a 20px gutter, which on a 780px phone
     * left 60-odd pixels of unused screen while the offer inside was being
     * squeezed to fit. On a phone a pop-up that nearly fills the display is
     * normal; a pop-up that scrolls is not. The gutter shrinks with it, since
     * 20px of backdrop on each side of a 360px screen is 11% of the width
     * spent on nothing.
     */
    .lf2-mode--modal { padding: 8px; }
    .lf2-mode--modal .lf2-panel { max-height: 96vh; }
    .lf2-mode--modal .lf2-col { padding: 20px 16px; }
    .lf2-mode--modal .lf2-body { gap: 8px; margin-top: 14px; }
    .lf2-mode--modal .lf2-heading { margin-bottom: 6px; }
    .lf2-mode--modal .lf2-subheading { margin-bottom: 4px; }

    /* The tier list is the tallest block on the announcement; it can afford to
       be a little tighter than it is on a desktop panel. */
    .lf2-mode--modal .lf2-tierrow { padding: 7px 10px; }
    .lf2-mode--modal .lf2-tierlist { gap: 1px; }
}

/**
 * ── Short screens, which is a different question from narrow ones ──
 *
 * A 360×900 phone has room to spare; a 360×640 does not, and it is the HEIGHT
 * that decides — so these key off height. Graduated across three steps rather
 * than one, because a single cliff at 700px was tuned against two devices and
 * a sweep across eight immediately found the gap: a 360×780 Galaxy and a
 * 390×844 iPhone are both too tall to qualify for the compaction and too short
 * to fit the cart nudge without it.
 *
 * The picture gives up the most at every step. A smaller photograph still reads
 * as the product; a clipped offer does not read as anything.
 */
@media (max-height: 900px) {
    .lf2-mode--modal .lf2-col { padding: 22px 18px; }
    .lf2-mode--modal .lf2-body { gap: 8px; margin-top: 12px; }
    .lf2-mode--modal .lf2-tierrow { padding: 6px 10px; }

    .lf2-mode--modal .lf2-cartitems { gap: 7px; margin-bottom: 12px; }
    .lf2-mode--modal .lf2-cartitem { padding: 7px; gap: 9px; }
    .lf2-mode--modal .lf2-cartitem-img { width: 46px; height: 46px; }

    .lf2-mode--modal .lf2-ladder { margin-bottom: 12px; }
}

/**
 * The picture's height is a STACKED-layout question, so it needs the width too.
 *
 * Keyed on height alone, these landed on any laptop: a 1366×768 screen has
 * about 650px of viewport, so a desktop pop-up — still side by side, where the
 * image column is supposed to stretch to the full height of the offer beside
 * it — got the phone's 22vh instead and rendered as a short block with white
 * space beneath it. Height alone says "there is not much room"; it does not say
 * "the image is now above the text rather than beside it", and only the second
 * one justifies overriding the height.
 */
@media (max-width: 640px) and (max-height: 900px) {
    .lf2-mode--modal .lf2-shell > .lf2-media { height: 22vh; }
}

@media (max-width: 640px) and (max-height: 700px) {
    .lf2-mode--modal .lf2-shell > .lf2-media { height: 18vh; min-height: 96px; }
}

/* A phone held sideways: the picture goes entirely. Width-guarded for the same
   reason as above — a short desktop window is still a side-by-side split, and
   there the image is doing its job. */
@media (max-width: 900px) and (max-height: 480px) {
    .lf2-mode--modal .lf2-shell > .lf2-media { display: none; }
}

@media (max-height: 700px) {
    .lf2-mode--modal { padding: 6px; }
    .lf2-mode--modal .lf2-panel { max-height: 97vh; }
    .lf2-mode--modal .lf2-col { padding: 14px 16px; }
    .lf2-mode--modal .lf2-body { gap: 6px; margin-top: 10px; }
    .lf2-mode--modal .lf2-heading { font-size: calc(var(--lf2-heading-size, 32px) * 0.66); }
    .lf2-mode--modal .lf2-tierrow { padding: 5px 10px; }
    .lf2-mode--modal .lf2-footnote { margin-top: 6px; }

    /**
     * The cart list is compacted, not hidden.
     *
     * On the cart nudge it is the single tallest block — two rows of 56px
     * thumbnails came to 138px of a 640px screen. Dropping it would be quicker
     * and would also silently override a block the operator switched on, so the
     * thumbnails shrink instead and the rows tighten. A shopper recognises
     * their own basket at 40px perfectly well.
     */
    .lf2-mode--modal .lf2-cartitems { gap: 6px; margin-bottom: 12px; }
    .lf2-mode--modal .lf2-cartitem { padding: 6px; gap: 8px; }
    .lf2-mode--modal .lf2-cartitem-img { width: 40px; height: 40px; }
    .lf2-mode--modal .lf2-cartitem-name { font-size: 13px; }
    .lf2-mode--modal .lf2-cartitem-price { font-size: 13px; }

    /* The ladder keeps its message and its track; the rung captions under the
       track are the part that can go, since the message already names the
       number they are there to label. */
    .lf2-mode--modal .lf2-ladder-head { font-size: 16px; margin-bottom: 10px; }
    .lf2-mode--modal .lf2-ladder { margin-bottom: 10px; }

    /* Gap suggestions scroll sideways rather than stacking a third row of the
       panel's height into the page. */
    .lf2-mode--modal .lf2-gapitems-grid {
        display: flex;
        overflow-x: auto;
        gap: 8px;
        scroll-snap-type: x mandatory;
    }
    .lf2-mode--modal .lf2-gapitem { flex: 0 0 42%; scroll-snap-align: start; }
}

/**
 * A phone held sideways, where the modal gets about 320px of height in total.
 *
 * The picture goes. Not compacted — gone. At this height a 45%-wide image
 * column leaves the offer perhaps 200px to say everything in, and a photograph
 * the shopper can barely see is not worth the sentence it displaces. It comes
 * straight back when they turn the phone upright.
 */
@media (max-height: 480px) {
    .lf2-mode--modal .lf2-col { padding: 12px 16px; }
    .lf2-mode--modal .lf2-body { gap: 5px; margin-top: 8px; }
    .lf2-mode--modal .lf2-badge { margin-bottom: 4px; }
    .lf2-mode--modal .lf2-heading { font-size: calc(var(--lf2-heading-size, 32px) * 0.56); margin-bottom: 4px; }
    .lf2-mode--modal .lf2-subheading { font-size: 13px; }
    .lf2-mode--modal .lf2-tierrow { padding: 4px 10px; font-size: 13px; }
    .lf2-mode--modal .lf2-cartitem-img { width: 34px; height: 34px; }
    .lf2-mode--modal .lf2-btn { padding-top: 10px; padding-bottom: 10px; }
    .lf2-mode--modal .lf2-footnote { display: none; }
}

/* ═══════════════════════════════════════════════════════════════
   CART BLOCKS — cart contents, reward threshold, countdown
   Every colour resolves from the same design tokens the rest of the
   funnel uses, so these blocks inherit a brand's theme automatically
   instead of needing their own palette.
   ═══════════════════════════════════════════════════════════════ */

.lf2-cartitems { display: flex; flex-direction: column; gap: 10px; width: 100%; margin-bottom: 18px; }

.lf2-cartitem {
    display: flex;
    align-items: center;
    gap: 12px;
    text-align: left;
    padding: 10px;
    border: 1px solid var(--lf2-option-border, #d9dce1);
    border-radius: var(--lf2-option-radius, 12px);
    background: var(--lf2-option-bg, #fff);
    color: var(--lf2-option-text, #16181d);
}
.lf2-cartitem-img { width: 56px; height: 56px; object-fit: cover; border-radius: 8px; flex: none; }
.lf2-cartitem-info { min-width: 0; flex: 1; }
.lf2-cartitem-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--lf2-option-text, #16181d);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.lf2-cartitem-price { font-size: 14px; margin-top: 2px; color: inherit; }
.lf2-cartitem-was { text-decoration: line-through; opacity: 0.5; margin-right: 6px; }
.lf2-cartitem-now { font-weight: 700; }
.lf2-cartitem-qty { font-size: 12px; color: inherit; opacity: 0.7; margin-top: 2px; }
.lf2-cartitem-more { font-size: 13px; color: var(--lf2-subheading-color, #6b7280); text-align: center; }

/* Reward threshold ------------------------------------------------ */

.lf2-threshold { width: 100%; margin-bottom: 18px; }
.lf2-threshold-label {
    font-size: 14px;
    font-weight: 600;
    margin-bottom: 8px;
    color: var(--lf2-heading-color, #16181d);
}
.lf2-threshold-label.lf2-is-met { color: var(--lf2-progress-fill, #16181d); }
.lf2-threshold-track {
    height: 8px;
    border-radius: 999px;
    overflow: hidden;
    background: var(--lf2-progress-track, #e6e8eb);
}
.lf2-threshold-fill {
    height: 100%;
    border-radius: 999px;
    background: var(--lf2-progress-fill, #16181d);
    transition: width 0.4s ease;
}

/* Countdown ------------------------------------------------------- */

.lf2-countdown { width: 100%; margin-bottom: 18px; text-align: center; }
.lf2-countdown-label { font-size: 14px; color: var(--lf2-subheading-color, #6b7280); margin-bottom: 8px; }
.lf2-countdown-face { display: flex; justify-content: center; gap: 10px; }

.lf2-countdown-cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    min-width: 72px;
    padding: 10px 8px;
    border: 1px solid var(--lf2-option-border, #d9dce1);
    border-radius: var(--lf2-option-radius, 12px);
}
.lf2-countdown-num {
    font-size: 30px;
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    color: var(--lf2-heading-color, #16181d);
}
.lf2-countdown-unit {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--lf2-subheading-color, #6b7280);
}
.lf2-countdown-inline {
    font-size: 14px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--lf2-heading-color, #16181d);
}

/* Offer ----------------------------------------------------------- */

.lf2-offer-note {
    font-size: 13px;
    color: var(--lf2-subheading-color, #6b7280);
    margin-bottom: 14px;
}

@media (max-width: 560px) {
    .lf2-countdown-cell { min-width: 60px; }
    .lf2-countdown-num { font-size: 24px; }
}

@media (prefers-reduced-motion: reduce) {
    .lf2-threshold-fill { transition: none; }
}
