/* ============================================
   Lovely homepage
   --------------------------------------------
   One idea per screen. The page scrolls in full-height sections that snap
   into place, each with its own reveal. Tokens and glass come from chrome.css.
   Only opacity, transform and filter are animated so motion stays smooth.
   ============================================ */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    scroll-snap-type: y mandatory;
    scroll-behavior: smooth;
    /* No rubber-band at the top or bottom of the page. On a phone, a flick
       into the footer used to run past the end, bounce, and settle back,
       which showed as the footer jumping up and down as it arrived. */
    overscroll-behavior-y: none;
    -webkit-text-size-adjust: 100%;
    background: var(--lv-black);
}

body.home {
    margin: 0;
    overflow-x: clip;
    font-family: var(--lv-font);
    color: var(--lv-white);
    background: var(--lv-black);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Zero-specificity reset, scoped to sections so the footer and cookie
   banner keep their own spacing. */
:where(.s) :where(h1, h2, h3, p, figure, blockquote) {
    margin: 0;
}

.s img {
    display: block;
}

@keyframes float {
    0%, 100% { transform: translate3d(0, 0, 0); }
    50% { transform: translate3d(0, -10px, 0); }
}

.home .lv-header {
    background: none;
}

/* --- Wave on phones ---------------------------------------------------------
   On a desktop the ribbons glide to a new place after each section. On a
   phone the page is dragged by a finger, back and forth, and those glides
   would keep changing course mid-flight. So here the ribbons follow one
   fixed path that is bound to the scroll position: a slow zigzag, one step
   per section. Scrolling up replays it exactly in reverse, and a ribbon is
   always on screen. Browsers without scroll-driven animations get the same
   path from home.js. */

@media (max-width: 860px), (hover: none) {
    .home .wave {
        transition: none;
    }

    @supports (animation-timeline: scroll()) {
        .home .wave {
            animation: home-wave-a linear both;
            animation-timeline: scroll(root block);
        }

        .home .wave--b {
            animation-name: home-wave-b;
        }
    }
}

@keyframes home-wave-a {
    0.00% { transform: translate3d(0, 60vh, 0) rotate(-5deg); }
    7.69% { transform: translate3d(0, 30vh, 0) rotate(0deg); }
    15.38% { transform: translate3d(0, 0vh, 0) rotate(5deg); }
    23.08% { transform: translate3d(0, 30vh, 0) rotate(0deg); }
    30.77% { transform: translate3d(0, 60vh, 0) rotate(-5deg); }
    38.46% { transform: translate3d(0, 30vh, 0) rotate(0deg); }
    46.15% { transform: translate3d(0, 0vh, 0) rotate(5deg); }
    53.85% { transform: translate3d(0, 30vh, 0) rotate(0deg); }
    61.54% { transform: translate3d(0, 60vh, 0) rotate(-5deg); }
    69.23% { transform: translate3d(0, 30vh, 0) rotate(0deg); }
    76.92% { transform: translate3d(0, 0vh, 0) rotate(5deg); }
    84.62% { transform: translate3d(0, 30vh, 0) rotate(0deg); }
    92.31% { transform: translate3d(0, 60vh, 0) rotate(-5deg); }
    100.00% { transform: translate3d(0, 30vh, 0) rotate(0deg); }
}

@keyframes home-wave-b {
    0.00% { transform: translate3d(0, -10vh, 0) rotate(5deg); }
    7.69% { transform: translate3d(0, 30vh, 0) rotate(0deg); }
    15.38% { transform: translate3d(0, 70vh, 0) rotate(-5deg); }
    23.08% { transform: translate3d(0, 30vh, 0) rotate(0deg); }
    30.77% { transform: translate3d(0, -10vh, 0) rotate(5deg); }
    38.46% { transform: translate3d(0, 30vh, 0) rotate(0deg); }
    46.15% { transform: translate3d(0, 70vh, 0) rotate(-5deg); }
    53.85% { transform: translate3d(0, 30vh, 0) rotate(0deg); }
    61.54% { transform: translate3d(0, -10vh, 0) rotate(5deg); }
    69.23% { transform: translate3d(0, 30vh, 0) rotate(0deg); }
    76.92% { transform: translate3d(0, 70vh, 0) rotate(-5deg); }
    84.62% { transform: translate3d(0, 30vh, 0) rotate(0deg); }
    92.31% { transform: translate3d(0, -10vh, 0) rotate(5deg); }
    100.00% { transform: translate3d(0, 30vh, 0) rotate(0deg); }
}

/* --- Sections -------------------------------------------------------------- */

.s {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    /* The large viewport: on phones the section still fills the screen once
       the browser toolbar has tucked away, so the next section never peeks in. */
    min-height: 100vh;
    min-height: 100lvh;
    padding: calc(var(--lv-header-h) + 8px) var(--lv-pad) clamp(20px, 4svh, 48px);
    overflow: hidden;
    scroll-snap-align: start;
    scroll-snap-stop: always;
}

.s-inner {
    width: 100%;
    max-width: var(--lv-max);
    margin: 0 auto;
}

/* The footer is the last stop: its bottom edge meets the bottom of the
   screen, which is simply the end of the page. */
.home .lv-footer {
    z-index: 1;
    scroll-snap-align: end;
    scroll-snap-stop: always;
}

/* On phones the footer is its own full screen: one scroll lands on all of
   it, wordmark included.

   It fills the large viewport, because by the time anyone has scrolled this
   far the browser's bars are tucked away and that is the screen they see.
   Mobile Safari keeps drawing the page behind its top bar, and the gap
   between the large and small viewports (100lvh - 100svh) is the height of
   those bars, so half of it is added as top padding to keep the first row
   clear of the address pill. Where the bars never move (in-app browsers) the
   two viewports are equal and the padding falls back to its base value. */
@media (max-width: 760px) {
    .home .lv-footer {
        display: flex;
        flex-direction: column;
        min-height: 100vh;
        min-height: 100lvh;
        padding-top: calc((100lvh - 100svh) * 0.5 + clamp(20px, 3lvh, 32px));
    }

    .home .lv-footer-inner {
        display: flex;
        flex: 1;
        flex-direction: column;
        width: 100%;
    }

    /* Any height left over is shared out around the brand row and the link
       lists (a half share above and below, a full one between), so there is
       never one large empty band. */
    .home .lv-footer-cols {
        flex: 1;
        align-content: space-around;
    }
}

/* --- Type ------------------------------------------------------------------ */

.s h1 {
    font-size: clamp(40px, 7.4vw, 84px);
    font-weight: 700;
    line-height: 1.02;
    letter-spacing: -0.04em;
    text-wrap: balance;
}

.s h2 {
    font-size: clamp(30px, 4.4vw, 52px);
    font-weight: 600;
    line-height: 1.08;
    letter-spacing: -0.035em;
    text-wrap: balance;
}

.s h1 em,
.s h2 em {
    font-style: normal;
    color: var(--lv-coral);
}

.duo span {
    color: rgba(255, 255, 255, 0.4);
}

.lede {
    max-width: 46ch;
    font-size: clamp(16px, 1.5vw, 19px);
    line-height: 1.55;
    color: rgba(255, 255, 255, 0.68);
    text-wrap: pretty;
}

.copy .lede {
    margin-top: 16px;
}

.eyebrow {
    margin-bottom: 14px;
    font-size: 14px;
    font-weight: 600;
    color: var(--lv-coral);
}

.fine {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.5);
}

.pill {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    width: fit-content;
    padding: 8px 15px;
    border-radius: 999px;
    font-size: 13px;
    font-weight: 600;
}

/* The store name in the pill can swap between stores: the outgoing word
   slides up and out, the next one rises in, and the pill eases to its width. */
.pill-text {
    white-space: nowrap;
}

.pill-swap {
    display: inline-grid;
    overflow: hidden;
    white-space: nowrap;
    vertical-align: bottom;
    transition: width 0.6s var(--lv-ease);
}

.pill-swap > span {
    grid-area: 1 / 1;
    justify-self: start;
    transition: opacity 0.5s var(--lv-ease), transform 0.6s var(--lv-ease);
}

.pill-swap > span:not(.is-on) {
    opacity: 0;
    transform: translate3d(0, 75%, 0);
}

.pill-swap > span.is-out {
    transform: translate3d(0, -75%, 0);
}

.pill-dot {
    position: relative;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--lv-coral);
}

/* A quiet ping on the live dot: a ring of the same color opens out to a
   little over twice the dot and fades, then rests before the next one. At
   its widest it is about 17px across, well inside the pill. */
.pill:not(.pill--soon) .pill-dot::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: var(--lv-coral);
    opacity: 0;
    animation: dot-ping 2.8s cubic-bezier(0.2, 0.6, 0.3, 1) infinite;
}

@keyframes dot-ping {
    0% { opacity: 0.45; transform: scale(1); }
    60%, 100% { opacity: 0; transform: scale(2.5); }
}

.pill--soon .pill-dot {
    background: var(--lv-sky);
}

.points {
    display: grid;
    gap: 12px;
    margin: 24px 0 0;
    padding: 0;
    list-style: none;
    font-size: 15px;
    font-weight: 500;
}

.points li {
    display: flex;
    align-items: center;
    gap: 12px;
}

.points .lv-i {
    font-size: 18px;
    color: var(--lv-coral);
}

/* Timed steps inside a mockup. They replay each time the section returns. */
.js [data-s] {
    opacity: 0;
    transform: translate3d(0, 0.9em, 0);
}

.js .is-live [data-s] {
    opacity: 1;
    transform: none;
    transition: opacity 0.7s var(--lv-ease) calc(var(--s) * 1ms), transform 0.8s var(--lv-ease) calc(var(--s) * 1ms);
}

@keyframes swap-out {
    to { opacity: 0; transform: scale(0.92); }
}

@keyframes swap-in {
    from { opacity: 0; transform: scale(0.92); }
    to { opacity: 1; transform: scale(1); }
}

/* --- Section dots (desktop) ------------------------------------------------
   Every dot is a circle. As a section arrives its dot stretches into a coral
   pill, and the dot being left shrinks back to a circle. Both are set from
   the scroll offset (--w runs 0 to 1), so the handover happens at exactly the
   pace of the page. The two always add up to one pill, so the column never
   changes length. */

.dots {
    position: fixed;
    top: 50%;
    right: 18px;
    z-index: 90;
    display: grid;
    gap: 10px;
    transform: translateY(-50%);
}

.dots button {
    position: relative;
    width: 8px;
    height: calc(8px + 18px * var(--w, 0));
    padding: 0;
    border: 0;
    border-radius: 99px;
    background: rgba(255, 255, 255, 0.22);
    background: color-mix(in srgb, var(--lv-coral) calc(var(--w, 0) * 100%), rgba(255, 255, 255, 0.22));
    cursor: pointer;
}

.dots button::before {
    content: '';
    position: absolute;
    inset: -6px -10px;
}

.dots button:focus-visible {
    outline: 2px solid var(--lv-sky);
    outline-offset: 3px;
}

@media (max-width: 1180px) {
    .dots {
        display: none;
    }
}

/* --- Phone -----------------------------------------------------------------
   Drawn in CSS so the screen inside can animate. Everything inside is sized
   in container units, so the whole device scales from one width. */

.phone {
    flex: none;
    width: var(--pw, 280px);
    container-type: inline-size;
}

.phone-body {
    position: relative;
    width: 100%;
    aspect-ratio: 300 / 630;
    padding: 3cqw;
    border-radius: 17cqw;
    background: linear-gradient(145deg, #6b6b6b, #303036 18%, #1c1c1f 50%, #3d3d44 85%, #6b6b6b);
    box-shadow: inset 0 0 0 0.5cqw rgba(255, 255, 255, 0.14), 0 14cqw 26cqw -8cqw rgba(0, 0, 0, 0.8);
}

.phone-screen {
    position: relative;
    height: 100%;
    overflow: hidden;
    border-radius: 14.2cqw;
    font-size: 4.35cqw;
    color: var(--lv-white);
    background: var(--lv-black);
    box-shadow: 0 0 0 1.3cqw #000;
}

.phone-island {
    position: absolute;
    top: 3cqw;
    left: 50%;
    z-index: 3;
    width: 29cqw;
    height: 8.4cqw;
    margin-left: -14.5cqw;
    border-radius: 99px;
    background: #000;
}

/* --- Real device frame ------------------------------------------------------
   Apple's iPhone 18 Pro bezel (iphone-frame.png, from Apple Design Resources)
   laid over the same live screen. The screen is positioned to the bezel's
   cutout, measured from the image: 5.42% in from each side, 2.53% from top
   and bottom, corner radius 14% of the screen width. It is set a hair larger
   so its edge tucks under the bezel. The bezel has its own Dynamic Island.
   To go back to the drawn frame, remove "phones-real" from <body>. */

.phones-real .phone-body {
    aspect-ratio: 831 / 1700;
    padding: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
}

.phones-real .phone-body::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 5;
    background: url('iphone-frame.png') center / 100% 100% no-repeat;
    pointer-events: none;
}

.phones-real .phone-screen {
    position: absolute;
    top: 2.3%;
    right: 5.1%;
    bottom: 2.3%;
    left: 5.1%;
    height: auto;
    border-radius: 12.9cqw;
    font-size: 4.15cqw;
    box-shadow: none;
}

.phones-real .phone-island {
    display: none;
}

/* Line the clock and battery up with the bezel's Dynamic Island. */
.phones-real .ui-status {
    padding-top: 0.75em;
}

/* --- App UI inside the phone ----------------------------------------------- */

.ui {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    gap: 0.75em;
    padding: 0 1.25em 1.2em;
    line-height: 1.3;
}

.ui strong {
    font-weight: 600;
}

.ui .lv-i {
    font-size: 1em;
}

.ui-status {
    display: flex;
    flex: none;
    align-items: center;
    justify-content: space-between;
    height: 3.3em;
    padding: 1.1em 0.7em 0;
    font-size: 0.86em;
    font-weight: 700;
}

.ui-batt {
    width: 1.7em;
    height: 0.8em;
    border-radius: 0.25em;
    background: var(--lv-white);
}

.ui-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 0.3em;
    font-size: 1.3em;
    letter-spacing: -0.02em;
}

.ui-bar strong {
    font-weight: 700;
}

.ui-bar > span:empty {
    width: 1em;
}

.ui-streak {
    display: inline-flex;
    align-items: center;
    gap: 0.2em;
    padding: 0.3em 0.55em;
    border-radius: 99px;
    font-size: 0.62em;
    font-weight: 700;
    background: rgba(255, 255, 255, 0.1);
}

.ui-streak .lv-i {
    color: var(--lv-coral);
}

.ui-week {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 0.2em;
    margin: 0.2em 0 0.5em;
    font-size: 0.8em;
    font-weight: 600;
    text-align: center;
}

.ui-week span {
    display: grid;
    gap: 0.1em;
    padding: 0.35em 0;
    border: 1px solid transparent;
    border-radius: 0.5em;
    color: rgba(255, 255, 255, 0.8);
}

.ui-week .is-today {
    color: var(--lv-white);
    background: rgba(255, 255, 255, 0.07);
    border-color: rgba(255, 255, 255, 0.35);
}

.ui-label {
    font-size: 0.72em;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.85);
}

.ui-center {
    align-self: center;
    text-align: center;
}

.ui-big {
    font-size: 1.28em;
    font-weight: 500;
    line-height: 1.2;
    letter-spacing: -0.02em;
}

.ui-muted {
    display: inline-flex;
    align-items: center;
    gap: 0.35em;
    font-size: 0.8em;
    color: rgba(255, 255, 255, 0.55);
}

.ui-cta,
.ui-done {
    display: inline-flex;
    align-items: center;
    align-self: center;
    gap: 0.4em;
    padding: 0.75em 1.5em;
    border-radius: 99px;
    font-size: 0.95em;
    font-weight: 700;
}

.ui-cta {
    background: var(--lv-coral);
}

.ui-done {
    color: var(--lv-sky);
    background: rgba(48, 188, 237, 0.1);
    border: 1px solid rgba(48, 188, 237, 0.5);
}

.ui-rule {
    flex: none;
    height: 1px;
    margin: 0.4em 0;
    background: rgba(255, 255, 255, 0.12);
}

.ui-card {
    display: grid;
    gap: 0.3em;
    padding: 0.9em 1em;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 1em;
    background: rgba(255, 255, 255, 0.055);
}

.ui-card strong {
    font-size: 1.05em;
}

.ui-card--lift {
    gap: 0.8em;
    padding: 1.1em;
    border-color: rgba(252, 81, 48, 0.45);
}

.ui-why {
    font-size: 0.8em;
    line-height: 1.4;
    color: rgba(255, 255, 255, 0.72);
}

.ui-why b {
    display: block;
    margin-bottom: 0.2em;
    font-weight: 700;
    color: var(--lv-almond);
}

.ui-avatar {
    display: grid;
    place-items: center;
    align-self: center;
    width: 3.4em;
    height: 3.4em;
    margin-top: 0.2em;
    border-radius: 50%;
    font-size: 1.3em;
    font-weight: 700;
    color: var(--lv-black);
    background: var(--lv-almond);
}

.ui-list {
    display: grid;
    gap: 0.45em;
    margin-top: 0.2em;
}

.ui-row {
    display: flex;
    justify-content: space-between;
    gap: 0.8em;
    padding: 0.7em 0.9em;
    border-radius: 0.8em;
    font-size: 0.82em;
    background: rgba(255, 255, 255, 0.055);
}

.ui-row span {
    color: rgba(255, 255, 255, 0.55);
}

.ui-row b {
    font-weight: 600;
    text-align: right;
}

.ui-toast {
    display: flex;
    align-items: center;
    gap: 0.7em;
    padding: 0.8em 0.9em;
    border: 1px solid rgba(48, 188, 237, 0.42);
    border-radius: 1em;
    font-size: 0.78em;
    line-height: 1.35;
    background: rgba(48, 188, 237, 0.14);
}

.ui-toast b {
    flex: none;
    padding: 0.45em 0.9em;
    border-radius: 99px;
    font-weight: 700;
    color: var(--lv-black);
    background: var(--lv-sky);
}

.ui-chips {
    display: flex;
    justify-content: center;
    gap: 0.5em;
    font-size: 0.8em;
    font-weight: 600;
}

.ui-chips span {
    padding: 0.55em 0.9em;
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 99px;
}

.ui-chips .is-picked {
    color: var(--lv-black);
    background: var(--lv-white);
    border-color: transparent;
}

.ui-bubble {
    max-width: 88%;
    padding: 0.7em 0.95em;
    border-radius: 1.1em;
    font-size: 0.9em;
    line-height: 1.35;
}

.ui-bubble--me {
    align-self: flex-end;
    min-height: 2.75em;
    margin-top: 0.3em;
    border-bottom-right-radius: 0.3em;
    font-weight: 500;
    color: var(--lv-black);
    background: var(--lv-almond);
}

.ui-reply {
    font-size: 0.9em;
    line-height: 1.45;
    color: rgba(255, 255, 255, 0.88);
}

.ui-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35em;
    margin-top: 0.2em;
}

.ui-tags i {
    padding: 0.3em 0.6em;
    border-radius: 99px;
    font-size: 0.7em;
    font-style: normal;
    font-weight: 600;
    color: var(--lv-almond);
    background: rgba(252, 81, 48, 0.18);
}

.ui-tags .is-sky {
    color: var(--lv-sky);
    background: rgba(48, 188, 237, 0.16);
}

/* A button that turns into its confirmed state. */
.ui-swap {
    display: grid;
    justify-items: center;
}

.ui-swap > * {
    grid-area: 1 / 1;
}

.js .ui-swap-b {
    opacity: 0;
}

.js .is-live .ui-swap-a {
    animation: swap-out 0.45s var(--lv-ease) calc(var(--s) * 1ms) forwards;
}

.js .is-live .ui-swap-b {
    animation: swap-in 0.6s var(--lv-ease) calc(var(--s) * 1ms + 250ms) forwards;
}

/* Typed text caret. */
[data-type]::after {
    content: '';
    display: inline-block;
    width: 1.5px;
    height: 1em;
    margin-left: 1px;
    vertical-align: -0.15em;
    background: currentColor;
    animation: blink 1s steps(1) infinite;
}

@keyframes blink {
    50% { opacity: 0; }
}

/* Lock screen with notifications. */
.ui-clock {
    margin: 0.25em 0 0.15em;
    font-size: 4.2em;
    font-weight: 600;
    line-height: 1;
    letter-spacing: -0.04em;
    text-align: center;
}

.ui-note {
    display: grid;
    gap: 0.2em;
    padding: 0.85em 1em;
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-radius: 1.2em;
    font-size: 0.82em;
    line-height: 1.35;
    background: rgba(255, 255, 255, 0.14);
}

.ui-note strong {
    font-weight: 700;
}

.ui-note-head {
    display: flex;
    align-items: center;
    gap: 0.4em;
    font-size: 0.85em;
    color: rgba(255, 255, 255, 0.6);
}

.ui-note-head img {
    width: 1.05em;
    height: 1.25em;
}

.ui-note-head i {
    margin-left: auto;
    font-style: normal;
}

/* --- Stage: the glass panel a phone sits in -------------------------------- */

.split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
    gap: clamp(28px, 6vw, 88px);
}

.split .stage {
    order: -1;
}

.split--flip .stage {
    order: 1;
}

.stage {
    display: flex;
    justify-content: center;
    height: min(74svh, 660px);
    padding-top: clamp(24px, 5svh, 48px);
    overflow: hidden;
    border-radius: 36px;
}

.stage .phone {
    --pw: min(300px, 64%, 40svh);
}

/* Fades the cropped phone into the panel instead of a hard edge. */
.stage:not(.stage--cards)::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 2;
    height: 22%;
    border-radius: 0 0 36px 36px;
    background: linear-gradient(to bottom, rgba(28, 28, 31, 0), rgba(28, 28, 31, 0.82));
    pointer-events: none;
}

/* Desktop: the phone is sized from the height of its panel, so it always
   fits whole and sits in the middle with the same margin above and below,
   whatever the height of the browser window. 56px is the two 28px margins;
   2.0457 is the bezel's height divided by its width. (On phones the panel is
   a different shape and the phone rises out of its bottom edge instead.) */
@media (min-width: 861px) {
    .stage {
        align-items: center;
        padding-top: 0;
    }

    .stage .phone {
        --pw: min(300px, 64%, calc((min(74svh, 660px) - 56px) / 2.0457));
    }

    .stage:not(.stage--cards)::after {
        display: none;
    }
}

/* --- 1. Hero ---------------------------------------------------------------- */

.s-hero {
    align-items: center;
    justify-content: flex-start;
    height: 100vh;
    height: 100lvh;
    min-height: 600px;
    padding-bottom: 0;
    text-align: center;
}

.hero-copy {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: clamp(14px, 2.2svh, 22px);
    max-width: 880px;
    padding-top: clamp(8px, 4.5svh, 56px);
}

.hero-cta {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    margin-top: 4px;
}

.hero-visual {
    display: flex;
    flex: 1;
    justify-content: center;
    width: 100%;
    min-height: 0;
    margin-top: clamp(16px, 3svh, 36px);
    padding-top: 8px;
    overflow: hidden;
    -webkit-mask-image: linear-gradient(to bottom, #000 68%, transparent);
    mask-image: linear-gradient(to bottom, #000 68%, transparent);
}

.hero-visual .phone {
    --pw: clamp(230px, 38svh, 330px);
}

/* --- 2. Hook ---------------------------------------------------------------- */

.hook-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: center;
    gap: clamp(28px, 6vw, 80px);
}

.hook-setup {
    display: grid;
    gap: 0.25em;
    font-size: clamp(24px, 3.2vw, 40px);
    font-weight: 500;
    line-height: 1.15;
    letter-spacing: -0.03em;
    color: rgba(255, 255, 255, 0.5);
}

.hook-setup span {
    display: block;
}

.hook-turn {
    display: grid;
    justify-items: start;
    gap: 18px;
}

.hook-turn h2 {
    font-size: clamp(34px, 4.8vw, 62px);
    font-weight: 700;
}

/* The three lines arrive together, then light up one at a time: the first
   two fade back, the last one stays lit. Then the answer appears. */
.js .s-hook .hook-setup [data-r] {
    transition-delay: calc(var(--i, 0) * 120ms + 60ms);
}

.js .s-hook .hook-turn [data-r] {
    transition-delay: calc(4.1s + (var(--i, 3) - 3) * 140ms);
}

.js .is-live .hook-setup span {
    animation: hook-pass 1.5s ease-in-out both;
}

.js .is-live .hook-setup span:nth-child(1) { animation-delay: 0.7s; }
.js .is-live .hook-setup span:nth-child(2) { animation-delay: 1.9s; }

.js .is-live .hook-setup span:nth-child(3) {
    animation-name: hook-stay;
    animation-duration: 1s;
    animation-delay: 3.1s;
}

@keyframes hook-pass {
    0%, 100% { color: rgba(255, 255, 255, 0.5); }
    40%, 60% { color: var(--lv-white); }
}

@keyframes hook-stay {
    from { color: rgba(255, 255, 255, 0.5); }
    to { color: var(--lv-white); }
}

/* --- 3. Promises ------------------------------------------------------------ */

.promises {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
    margin-top: clamp(24px, 5svh, 48px);
}

.promise {
    display: flex;
    flex-direction: column;
    padding: 14px 14px 26px;
    border-radius: 28px;
}

.promise-visual {
    position: relative;
    display: grid;
    place-items: center;
    height: clamp(140px, 26svh, 230px);
    margin-bottom: 20px;
    overflow: hidden;
    border-radius: 18px;
    background: rgba(0, 0, 0, 0.28);
}

.promise h3 {
    padding: 0 8px;
    font-size: clamp(18px, 1.7vw, 21px);
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -0.02em;
}

.promise > p {
    padding: 8px 8px 0;
    font-size: 15px;
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.6);
}

.mini {
    display: grid;
    gap: 5px;
    width: min(230px, 82%);
    padding: 14px 16px;
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 16px;
    font-size: 13px;
    background: rgba(255, 255, 255, 0.09);
    box-shadow: 0 18px 30px -16px rgba(0, 0, 0, 0.7);
    animation: float 6s ease-in-out infinite;
}

.promise:nth-child(2) .mini { animation-delay: -2s; }
.promise:nth-child(3) .mini { animation-delay: -4s; }

.mini strong {
    font-size: 16px;
    font-weight: 600;
    letter-spacing: -0.01em;
}

.mini-tag {
    width: fit-content;
    padding: 3px 8px;
    border-radius: 99px;
    font-size: 11px;
    font-weight: 700;
    color: var(--lv-almond);
    background: rgba(252, 81, 48, 0.2);
}

.mini-row {
    display: flex;
    align-items: center;
    gap: 6px;
    color: rgba(255, 255, 255, 0.6);
}

.mini-row .lv-i {
    color: var(--lv-coral);
}

.mini-app {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: rgba(255, 255, 255, 0.6);
}

.mini-app img {
    width: 13px;
    height: 16px;
}

.mini-app i {
    margin-left: auto;
    font-style: normal;
}

/* --- 7. Tabs ----------------------------------------------------------------
   One tab is open at a time. A thin track under its title fills as the timer
   runs, then the next tab opens and the phone swaps screens. */

.tabs {
    display: grid;
    gap: 6px;
    margin: clamp(18px, 4svh, 40px) 0 0;
    padding: 0;
    list-style: none;
}

.tab-title {
    display: block;
    padding: 6px 0;
    border: 0;
    font-family: inherit;
    font-size: clamp(22px, 2.6vw, 30px);
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: -0.03em;
    text-align: left;
    color: var(--lv-white);
    background: none;
    opacity: 0.3;
    cursor: pointer;
    transition: opacity 0.3s var(--lv-ease);
    -webkit-tap-highlight-color: transparent;
}

.tab.is-active .tab-title {
    opacity: 1;
}

@media (hover: hover) {
    .tab:not(.is-active) .tab-title:hover {
        opacity: 0.6;
    }
}

.tab-title:focus-visible {
    outline: 2px solid var(--lv-sky);
    outline-offset: 2px;
    border-radius: 6px;
}

.tab-panel {
    display: grid;
    grid-template-rows: 1fr;
}

.tab-panel-inner {
    min-height: 0;
    overflow: hidden;
}

.js .tab-panel {
    grid-template-rows: 0fr;
    opacity: 0;
    transition: grid-template-rows 0.55s var(--lv-ease), opacity 0.45s var(--lv-ease);
}

.js .tab.is-active .tab-panel {
    grid-template-rows: 1fr;
    opacity: 1;
}

.tab-track {
    width: 160px;
    height: 2px;
    margin-top: 6px;
    overflow: hidden;
    border-radius: 99px;
    background: rgba(255, 255, 255, 0.14);
}

.tab-fill {
    display: block;
    height: 100%;
    border-radius: 99px;
    background: var(--lv-white);
    transform: scaleX(var(--p, 0));
    transform-origin: left;
}

.tab-points {
    display: grid;
    gap: 8px;
    margin: 0;
    padding: 14px 0 10px;
    list-style: none;
    font-size: 16px;
    line-height: 1.4;
    color: rgba(255, 255, 255, 0.75);
}

.tab-points li {
    display: flex;
    align-items: flex-start;
    gap: 10px;
}

.tab-points .lv-i {
    margin-top: 0.15em;
    font-size: 17px;
    color: var(--lv-coral);
}

.js .tabscreen {
    opacity: 0;
    transition: opacity 0.6s var(--lv-ease);
}

.js .tabscreen.is-on {
    opacity: 1;
}

.js .tabscreen:not(.is-on) [data-s] {
    opacity: 0;
    transform: translate3d(0, 0.9em, 0);
    transition: none;
}

.tabscreen--lock {
    background: var(--lv-graphite);
}

/* --- 8. Do it for me -------------------------------------------------------- */

.s-doit .pill {
    margin-bottom: 18px;
}

.s-doit .lede {
    margin-top: 16px;
}

/* A task waiting for a yes: icon, what it is, and the Approve button that
   turns into Approved. */
.ui-task {
    display: flex;
    align-items: center;
    gap: 0.7em;
    padding: 0.75em 0.8em;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 1em;
    background: rgba(255, 255, 255, 0.055);
}

.ui-task-icon {
    display: grid;
    flex: none;
    place-items: center;
    width: 2.3em;
    height: 2.3em;
    border-radius: 0.7em;
    color: var(--lv-coral);
    background: rgba(252, 81, 48, 0.16);
}

.ui-task-text {
    display: grid;
    flex: 1;
    gap: 0.15em;
    min-width: 0;
    font-size: 0.72em;
    line-height: 1.3;
    color: rgba(255, 255, 255, 0.55);
}

.ui-task-text strong {
    font-size: 1.3em;
    color: var(--lv-white);
}

.ui-task .ui-swap {
    flex: none;
}

.ui-ok {
    display: inline-flex;
    align-items: center;
    gap: 0.3em;
    padding: 0.55em 0.9em;
    border-radius: 99px;
    font-size: 0.7em;
    font-weight: 700;
    background: var(--lv-coral);
}

.ui-ok--done {
    color: var(--lv-sky);
    background: rgba(48, 188, 237, 0.12);
    box-shadow: inset 0 0 0 1px rgba(48, 188, 237, 0.5);
}

/* --- 9. Compare -------------------------------------------------------------- */

.s-compare h2 {
    margin-left: auto;
    margin-right: auto;
    text-align: center;
}

.compare {
    display: grid;
    grid-template-columns: 1fr 1.15fr;
    align-items: stretch;
    gap: 20px;
    max-width: 920px;
    margin: clamp(24px, 5svh, 44px) auto 0;
}

.compare-col {
    padding: clamp(20px, 3vw, 32px);
    border-radius: 28px;
}

.compare-col:not(.lv-glass) {
    border: 1px solid rgba(255, 255, 255, 0.08);
    background: rgba(0, 0, 0, 0.22);
}

.compare-col h3 {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 18px;
    font-size: 18px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.5);
}

.compare-col h3 img {
    width: 20px;
    height: 24px;
}

.compare-col ul {
    display: grid;
    gap: 14px;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: clamp(15px, 1.4vw, 17px);
    font-weight: 500;
    color: rgba(255, 255, 255, 0.5);
}

.compare-col li {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    line-height: 1.35;
}

.compare-col .lv-i {
    margin-top: 0.1em;
    font-size: 18px;
    color: rgba(255, 255, 255, 0.3);
}

.compare-col--lovely h3,
.compare-col--lovely ul {
    color: var(--lv-white);
}

.compare-col--lovely .lv-i {
    color: var(--lv-coral);
}

/* --- 10. Reviews -------------------------------------------------------------- */

.s-reviews {
    padding-left: 0;
    padding-right: 0;
}

.s-reviews .s-inner {
    padding: 0 var(--lv-pad);
}

.reviews {
    display: grid;
    gap: 20px;
    margin-top: clamp(24px, 5svh, 48px);
    -webkit-mask-image: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
    mask-image: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
}

.reviews-row {
    display: flex;
    overflow: hidden;
}

.reviews-track {
    display: flex;
    flex: none;
    gap: 20px;
    width: max-content;
    padding-right: 20px;
}

.js .reviews-track {
    animation: marquee var(--dur, 60s) linear infinite;
}

.js .reviews-row--rev .reviews-track {
    animation-direction: reverse;
}

@keyframes marquee {
    to { transform: translate3d(-50%, 0, 0); }
}

/* Cards are always moving, so they skip the live backdrop blur. */
.review.lv-glass {
    display: flex;
    flex: none;
    flex-direction: column;
    gap: 12px;
    width: min(440px, 82vw);
    padding: 22px 24px;
    border-radius: 22px;
    background: rgba(48, 48, 54, 0.92);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

.stars {
    display: flex;
    gap: 3px;
    font-size: 15px;
    color: var(--lv-gold);
}

.review blockquote {
    font-size: 16px;
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.9);
}

.review .stars {
    margin-left: auto;
}

.review figcaption {
    display: flex;
    align-items: center;
    gap: 12px;
    font-size: 13px;
    color: rgba(255, 255, 255, 0.5);
}

.review figcaption strong {
    display: block;
    font-size: 15px;
    font-weight: 600;
    color: var(--lv-white);
}

.review-avatar {
    display: grid;
    flex: none;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    font-size: 13px;
    font-weight: 700;
    color: var(--lv-black);
    background: var(--lv-almond);
}

/* --- 11. Pricing --------------------------------------------------------------- */

.s-pricing {
    text-align: center;
}

.plans {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 360px));
    justify-content: center;
    gap: 20px;
    margin-top: clamp(24px, 5svh, 48px);
}

.plan {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: clamp(28px, 3.4vw, 40px) clamp(22px, 3vw, 32px) clamp(22px, 3vw, 32px);
    border-radius: 28px;
}

.plan--best {
    border-color: var(--lv-coral);
}

.plan h3 {
    font-size: 16px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.6);
}

.plan-flag {
    position: absolute;
    top: 0;
    left: 50%;
    padding: 6px 12px;
    border-radius: 99px;
    font-size: 12px;
    font-weight: 700;
    white-space: nowrap;
    background: var(--lv-coral);
    transform: translate(-50%, -50%);
}

.plan-price {
    font-size: clamp(40px, 5vw, 56px);
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.04em;
}

.plan-price span {
    margin-left: 4px;
    font-size: 0.32em;
    font-weight: 500;
    letter-spacing: 0;
    color: rgba(255, 255, 255, 0.5);
}

.plan-note {
    margin-bottom: 16px;
    font-size: 14px;
    color: rgba(255, 255, 255, 0.55);
}

.plan .lv-btn {
    width: 100%;
    margin-top: auto;
}

/* --- 12. FAQ --------------------------------------------------------------------- */

.faq-grid {
    display: grid;
    grid-template-columns: 0.8fr 1.2fr;
    align-items: start;
    gap: clamp(24px, 6vw, 80px);
}

.faq-item {
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.faq-item button {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    width: 100%;
    padding: 18px 0;
    border: 0;
    font-family: var(--lv-font);
    font-size: clamp(16px, 1.5vw, 19px);
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: -0.01em;
    text-align: left;
    color: var(--lv-white);
    background: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.faq-item button:focus-visible {
    outline: 2px solid var(--lv-sky);
    outline-offset: 2px;
    border-radius: 6px;
}

.faq-item .lv-i {
    font-size: 20px;
    color: var(--lv-coral);
    transition: transform 0.5s var(--lv-ease);
}

.faq-item button[aria-expanded="true"] .lv-i {
    transform: rotate(45deg);
}

.faq-a {
    display: grid;
    grid-template-rows: 1fr;
}

.faq-a p {
    min-height: 0;
    overflow: hidden;
    font-size: 16px;
    line-height: 1.6;
    color: rgba(255, 255, 255, 0.65);
}

.faq-a p::after {
    content: '';
    display: block;
    height: 18px;
}

.js .faq-a {
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.55s var(--lv-ease);
}

.js .faq-item.is-open .faq-a {
    grid-template-rows: 1fr;
}

/* --- 13. Final ----------------------------------------------------------------------- */

.final {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: clamp(14px, 2.4svh, 24px);
    text-align: center;
}

.final-logo {
    width: 60px;
    height: 72px;
}

.s-final h2 {
    font-size: clamp(38px, 6.4vw, 76px);
    font-weight: 700;
}

/* --- Tablet and phone -------------------------------------------------------------------
   Copy first, then the phone rising from the bottom edge of the screen. */

@media (max-width: 860px) {
    :root {
        --lv-header-h: 64px;
    }

    .s-feature,
    .s-work,
    .s-doit {
        justify-content: flex-start;
        height: 100vh;
        height: 100lvh;
        min-height: 640px;
        padding-bottom: 0;
    }

    .s-feature .copy,
    .s-work .copy,
    .s-doit .copy {
        padding-top: clamp(4px, 2svh, 20px);
    }

    .s-inner.split {
        display: flex;
        flex: 1;
        flex-direction: column;
        align-items: stretch;
        gap: 22px;
        min-height: 0;
    }

    .split .stage,
    .split--flip .stage {
        flex: 1 1 0;
        order: 1;
        height: auto;
        min-height: 240px;
        border-bottom: 0;
        border-radius: 28px 28px 0 0;
    }

    .stage .phone {
        --pw: min(270px, 70%);
    }

    /* Wherever the screen ends, the panel and the phone in it fade away
       rather than stopping at a hard line. */
    .split .stage,
    .split--flip .stage {
        -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 150px), transparent calc(100% - 6px));
        mask-image: linear-gradient(to bottom, #000 calc(100% - 150px), transparent calc(100% - 6px));
    }

    .stage:not(.stage--cards)::after {
        display: none;
    }

    /* Centered sections sit a little above the middle on phones: the bottom
       of the screen is the least comfortable place to read, and the browser
       toolbar can cover it. */
    .s-hook,
    .s-intro,
    .s-compare,
    .s-reviews,
    .s-pricing,
    .s-faq,
    .s-final {
        justify-content: flex-start;
        padding-top: calc(var(--lv-header-h) + clamp(14px, 3.5lvh, 32px));
        padding-bottom: 32px;
    }

    /* The two sparse screens keep a little more air above them, so they do
       not look pinned to the header. */
    .s-hook {
        padding-top: calc(var(--lv-header-h) + clamp(28px, 8lvh, 76px));
    }

    /* Centered in the part of the screen that is always visible. Mobile
       Safari's large viewport runs on below its bars, so centering in the
       full section would sit low; the difference between the large and small
       viewports is taken off the bottom first. */
    .s-final {
        justify-content: center;
        padding-top: var(--lv-header-h);
        padding-bottom: calc(100lvh - 100svh + clamp(40px, 8svh, 76px));
    }

    .hook-grid {
        grid-template-columns: 1fr;
        gap: clamp(28px, 6svh, 48px);
    }

    /* Promises become a swipeable row. */
    .promises {
        display: flex;
        gap: 12px;
        margin-left: calc(var(--lv-pad) * -1);
        margin-right: calc(var(--lv-pad) * -1);
        padding: 0 var(--lv-pad) 6px;
        overflow-x: auto;
        scroll-snap-type: x mandatory;
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
    }

    .promises::-webkit-scrollbar {
        display: none;
    }

    .promise {
        flex: 0 0 min(78vw, 320px);
        scroll-snap-align: center;
    }

    .compare {
        grid-template-columns: 1fr;
        gap: 12px;
    }

    .compare-col {
        padding: 18px 20px;
    }

    .compare-col h3 {
        margin-bottom: 12px;
        font-size: 16px;
    }

    .compare-col ul {
        gap: 10px;
    }

    /* A mask over moving cards is repainted every frame; at this width the
       fade would only be a few pixels wide, so the rows just run edge to edge. */
    .reviews {
        gap: 12px;
        -webkit-mask-image: none;
        mask-image: none;
    }

    .reviews-track {
        gap: 12px;
        padding-right: 12px;
    }

    .review.lv-glass {
        padding: 18px 20px;
    }

    .review blockquote {
        font-size: 15px;
    }

    .plans {
        grid-template-columns: 1fr;
        gap: 24px;
    }

    .plan {
        padding: 20px;
    }

    .plan-note {
        margin-bottom: 10px;
    }

    .faq-grid {
        grid-template-columns: 1fr;
        gap: 12px;
    }

    .faq-item button {
        padding: 15px 0;
    }
}

/* Short phones (iPhone SE and similar): the product has to stay on screen,
   so the copy tightens up and secondary lines step aside. */
@media (max-width: 860px) and (max-height: 740px) {
    .s-feature .points,
    .s-doit .points,
    .hero-cta .fine,
    .tab-points {
        display: none;
    }

    .s h1 {
        font-size: clamp(31px, 9.2vw, 38px);
    }

    .s h2 {
        font-size: clamp(26px, 7.6vw, 30px);
    }

    .hero-copy {
        gap: 12px;
        padding-top: 2px;
    }

    .s .lede {
        font-size: 15px;
    }

    .hero-visual {
        margin-top: 16px;
    }

    .hero-visual .phone {
        --pw: clamp(210px, 62vw, 260px);
    }

    .tabs {
        gap: 0;
        margin-top: 12px;
    }

    .tab-title {
        padding: 4px 0;
        font-size: 21px;
    }

    .tab-track {
        margin-bottom: 8px;
    }

    .s-inner.split {
        gap: 16px;
    }
}

/* Very short viewports (landscape phones): let the page scroll freely. */
@media (max-height: 520px) {
    html {
        scroll-snap-type: none;
    }
}

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

@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior: auto;
        scroll-snap-type: y proximity;
    }

    .js [data-s] {
        opacity: 1;
        transform: none;
        transition: none;
    }

    .home .wave,
    .pill .pill-dot::after,
    .mini,
    .final-logo,
    .hero-visual .phone,
    [data-type]::after {
        animation: none;
        transition: none;
    }

    .js .is-live .ui-swap-a,
    .js .is-live .ui-swap-b,
    .is-live .tab.is-active .tab-title::after {
        animation-duration: 0.01ms;
        animation-delay: 0ms;
    }

    .js .reviews-track,
    .js .is-live .hook-setup span {
        animation: none;
    }

    .hook-setup span:last-child {
        color: var(--lv-white);
    }

    .reviews-row {
        overflow-x: auto;
    }
}
