/* ==========================================================================
   Launch film
   --------------------------------------------------------------------------
   Homepage (#launch-video): a vanilla port of 21st.dev's "Scroll Expansion
   Hero" (ScrollExpandMedia). Behaviour lives in scripts/launch-film.js, which
   writes one number, --lf-p (0 = small card, 1 = full size), plus the frame's
   pixel size. Everything else here is derived from --lf-p.

   Watch page (launch-video.html): the .lv-* rules at the bottom.

   The film is a web encode of Motion Graphics/AtListen Launch/AtListen-Launch.mp4
   (see media/ and the "Launch film" section of CLAUDE.md).
   ========================================================================== */

.lf-section {
    --lf-p: 0;
    --lf-top: 88px;               /* the fixed nav's bottom edge; measured by JS */
    position: relative;
    height: 230vh;                /* sticky travel: ~1 screen to expand, the rest to watch */
    background: #070816;
    color: #fff;
}

/* The stage sits just below the fixed nav for the whole section. It clips its own
   contents (the title words fly off-screen) -- overflow on the STAGE, never on the
   section: an overflow:hidden ancestor would become the scroll container and sticky
   would stop sticking. The clip also stops the off-screen words from widening a
   phone's layout viewport. */
.lf-stage {
    position: sticky;
    top: var(--lf-top);
    height: calc(100vh - var(--lf-top));
    height: calc(100svh - var(--lf-top));
    overflow: hidden;
    contain: paint;
}

/* The original's background image, as brand-gradient light on deep navy plus the
   hero's dot texture. It fades out as the film opens, leaving a dark "theatre". */
.lf-backdrop {
    position: absolute;
    inset: 0;
    opacity: calc(1 - var(--lf-p));
    background:
        radial-gradient(55% 50% at 18% 28%, rgba(139, 92, 246, 0.38), transparent 70%),
        radial-gradient(50% 45% at 84% 74%, rgba(16, 185, 129, 0.24), transparent 70%),
        radial-gradient(70% 60% at 50% 50%, rgba(59, 130, 246, 0.26), transparent 72%),
        #0b0d22;
}

.lf-backdrop::after {
    content: '';
    position: absolute;
    inset: 0;
    background-image: radial-gradient(rgba(255, 255, 255, 0.14) 1px, transparent 1.5px);
    background-size: 22px 22px;
    -webkit-mask-image: radial-gradient(ellipse at center, #000 25%, transparent 72%);
    mask-image: radial-gradient(ellipse at center, #000 25%, transparent 72%);
}

/* Sized in px by JS every frame (300x400 card -> 16:9 at ~95vw / 85% height). */
.lf-frame {
    opacity: var(--lf-show, 1);   /* JS: 0 until the visitor scrolls (see .lf-heading) */
    position: absolute;
    left: 50%;
    top: 50%;
    width: 300px;
    height: 400px;
    transform: translate(-50%, calc(-50% - var(--lf-lift, 0px)));
    z-index: 1;
}

.lf-media {
    position: absolute;
    inset: 0;
    overflow: hidden;
    border-radius: 18px;
    background: #05060f;
    box-shadow:
        0 0 50px rgba(0, 0, 0, 0.3),
        0 30px 120px -24px rgba(59, 130, 246, 0.45),
        0 0 0 1px rgba(255, 255, 255, 0.08);
}

.lf-video {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    cursor: pointer;
}

/* The glass title card fills the stage (scripts/glass-headline.js). The wrapper takes the
   scroll-driven fade (JS writes its opacity every frame, so no transition on it); the canvas
   inside fades in once, when the glass is ready. Without WebGL2 neither shows and the CSS
   backdrop and headline below do the job. */
.lf-glass {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

.lf-glass-canvas {
    display: block;
    width: 100%;
    height: 100%;
    opacity: 0;
    transition: opacity 700ms cubic-bezier(0.23, 1, 0.32, 1);
}

.lf-section[data-glass="true"] .lf-glass-canvas { opacity: 1; }
.lf-section[data-glass="true"] .lf-backdrop { opacity: 0; }

/* The title card: an eyebrow, the headline over two lines, and the scroll hint. The film is NOT
   behind it: it stays hidden (--lf-show) until the parting title has opened a gap for it. */
.lf-heading {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-5);
    pointer-events: none;
}

.lf-kicker,
.lf-hint {
    margin: 0;
    opacity: calc(1 - var(--lf-split, 0) * 3);
    transform: translateY(calc(var(--lf-split, 0) * -24px));
}

.lf-kicker {
    display: inline-flex;
    align-items: center;
    height: 30px;
    padding: 0 14px;
    border-radius: 999px;
    font-size: var(--text-xs);
    font-weight: var(--font-semibold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.85);
    border: 1px solid rgba(255, 255, 255, 0.2);
    background: rgba(255, 255, 255, 0.07);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
}

.lf-hint {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: var(--text-sm);
    font-weight: var(--font-medium);
    color: rgba(219, 234, 254, 0.75);
}

.lf-hint svg { width: 14px; height: 14px; }

.lf-title {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.04em;
    margin: 0;
    /* Big on purpose: glass needs stroke width to bend anything. Below ~60px the strokes read as
       outlined text rather than thick glass, so phones get 4rem, not the usual scale. */
    font-size: clamp(4rem, 14vw, 9.5rem);
    font-weight: var(--font-bold);
    line-height: 0.95;
    letter-spacing: -0.025em;
    text-align: center;
}

/* filter on the SAME element as the gradient clip, never an ancestor: a filter or
   transform on a parent of background-clip:text renders the text invisible. */
.lf-word {
    display: block;
    color: #fff;
    filter: drop-shadow(0 4px 24px rgba(0, 0, 0, 0.45));
    transition: opacity 900ms cubic-bezier(0.23, 1, 0.32, 1);
    will-change: transform;
}

/* Without WebGL2 the CSS words do the parting themselves. */
.lf-word-a { transform: translateX(calc(var(--lf-split, 0) * -85vw)); }
.lf-word-b { transform: translateX(calc(var(--lf-split, 0) * 85vw)); }

/* With the glass live, the words are there only for search engines and screen readers. They stay
   put -- the shader does the parting, and the glass is measured from where they rest -- and go
   clear, melting into the glass as it forms. */
.lf-section[data-glass] .lf-word { transform: none; }
.lf-section[data-glass="true"] .lf-word { opacity: 0; }

/* Controls: always focusable (a hidden-but-focusable control would trap no one, and
   WCAG 2.2.2 needs a pause for motion over 5s), shown once open, on hover, or on focus.
   Bottom-LEFT on purpose: the fixed "Ask AI" launcher owns the bottom-right corner. */
.lf-controls {
    --lf-cx: 0px;                 /* horizontal centring offset; phones set -50% */
    position: absolute;
    left: 14px;
    bottom: 14px;
    z-index: 3;
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 5px;
    border-radius: 999px;
    background: rgba(8, 10, 26, 0.6);
    border: 1px solid rgba(255, 255, 255, 0.14);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    opacity: 0;
    transform: translate(var(--lf-cx), 6px);
    transition: opacity var(--duration-normal) var(--ease-out),
                transform var(--duration-normal) var(--ease-out);
}

.lf-section.lf-open .lf-controls,
.lf-frame:hover .lf-controls,
.lf-controls:focus-within {
    opacity: 1;
    transform: translate(var(--lf-cx), 0);
}

.lf-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-width: 44px;
    min-height: 44px;
    padding: 0 12px;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: #fff;
    font: inherit;
    font-size: var(--text-sm);
    font-weight: var(--font-semibold);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out);
}

.lf-btn:hover { background: rgba(255, 255, 255, 0.12); }

.lf-btn:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}

.lf-btn svg {
    width: 20px;
    height: 20px;
    flex: none;
}

.lf-btn-icon { padding: 0; }

.lf-btn-sound {
    background: var(--gradient-brand);
    padding: 0 16px;
}

.lf-btn-sound:hover { background: var(--gradient-brand); filter: brightness(1.1); }

.lf-btn-sound[data-sound="on"] { background: rgba(255, 255, 255, 0.12); }

/* Exactly one icon of each pair shows, keyed off the state JS writes. */
.lf-ico-pause { display: none; }
.lf-section[data-playing="true"] .lf-ico-pause { display: block; }
.lf-section[data-playing="true"] .lf-ico-play { display: none; }
.lf-ico-sound-on { display: none; }
.lf-btn-sound[data-sound="on"] .lf-ico-sound-on { display: block; }
.lf-btn-sound[data-sound="on"] .lf-ico-sound-off { display: none; }

.lf-btn[hidden] { display: none; }

/* Under the open film: what it is, and the watch page with chapters. */
.lf-caption {
    position: absolute;
    left: 50%;
    top: calc(100% + 6px);
    z-index: 2;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 6px 16px;
    width: max-content;
    max-width: calc(100% - 32px);
    margin: 0;
    font-size: var(--text-sm);
    color: rgba(255, 255, 255, 0.7);
    transform: translateX(-50%);
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--duration-slow) var(--ease-out), visibility 0s linear var(--duration-slow);
}

.lf-section.lf-open .lf-caption,
.lf-section.lf-static .lf-caption {
    opacity: 1;
    visibility: visible;
    transition: opacity var(--duration-slow) var(--ease-out);
}

.lf-caption a {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-height: 32px;
    color: #fff;
    font-weight: var(--font-semibold);
    text-decoration: underline;
    text-decoration-color: rgba(255, 255, 255, 0.35);
    text-underline-offset: 4px;
}

.lf-caption a:hover { text-decoration-color: #fff; }

/* Touch: a full 44px target on the one link. Keyed on the pointer, not a width, so a phone
   in landscape gets it too. */
@media (pointer: coarse) {
    .lf-caption a { min-height: 44px; }
}

/* Phones: a 16:9 film is only ~208px tall in portrait, so an overlaid control bar would hide a
   quarter of it -- and the "Ask AI" launcher owns the bottom-right corner. Controls and caption
   move into the empty space BELOW the film instead. */
@media (max-width: 767px) {
    .lf-section { height: 200vh; }
    .lf-controls {
        --lf-cx: -50%;
        left: 50%;
        top: calc(100% + 14px);
        bottom: auto;
    }
    .lf-caption { top: calc(100% + 74px); }
}

/* Reduced motion (JS adds .lf-static): no scroll-driven growth and no autoplay. The
   heading sits above a full-width player, which waits for a press of Play. */
.lf-section.lf-static { height: auto; }

.lf-static .lf-stage {
    position: relative;
    top: auto;
    height: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-8);
    padding: var(--space-24) var(--space-4) var(--space-16);
}

.lf-static .lf-backdrop { opacity: 0.55; }

.lf-static .lf-heading {
    position: relative;
    inset: auto;
    order: -1;                    /* after the frame in the markup; above it on screen */
}

.lf-static .lf-title { flex-direction: row; flex-wrap: wrap; gap: 0 0.25em; }
.lf-static .lf-word { transform: none; }

.lf-static .lf-frame {
    opacity: 1;
    position: relative;
    left: auto;
    top: auto;
    width: min(100%, 1200px);
    height: auto;
    aspect-ratio: 16 / 9;
    transform: none;
}

/* Reduced motion gets the browser's own controls (JS sets video.controls): fully accessible
   at any size, and no overlay of ours to fade in. */
.lf-static .lf-hint,
.lf-static .lf-controls { display: none; }

.lf-static .lf-caption { top: calc(100% + 8px); }

/* ==========================================================================
   Watch page (launch-video.html)
   ========================================================================== */

.lv-section {
    padding: calc(var(--nav-height) + var(--space-8)) 0 var(--space-20);
    background: var(--color-bg-primary);
}

.lv-container {
    width: min(100% - 32px, 1120px);
    margin: 0 auto;
}

.lv-header { margin: var(--space-6) 0 var(--space-8); }

.lv-title {
    margin: 0 0 var(--space-3);
    font-size: clamp(2rem, 4.5vw, var(--text-5xl));
    font-weight: var(--font-bold);
    line-height: var(--leading-tight);
    letter-spacing: -0.02em;
    color: var(--color-text-primary);
}

.lv-lede {
    max-width: 62ch;
    margin: 0;
    font-size: var(--text-lg);
    line-height: var(--leading-relaxed);
    color: var(--color-text-secondary);
}

.lv-player {
    position: relative;
    overflow: hidden;
    border-radius: 18px;
    background: #05060f;
    aspect-ratio: 16 / 9;
    box-shadow: 0 30px 80px -30px rgba(59, 130, 246, 0.45), 0 0 0 1px rgba(15, 23, 42, 0.08);
}

.lv-player video {
    display: block;
    width: 100%;
    height: 100%;
}

.lv-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-10);
    margin-top: var(--space-12);
}

.lv-grid h2 {
    margin: 0 0 var(--space-4);
    font-size: var(--text-2xl);
    font-weight: var(--font-bold);
    color: var(--color-text-primary);
}

.lv-grid p {
    margin: 0 0 var(--space-4);
    line-height: var(--leading-relaxed);
    color: var(--color-text-secondary);
}

.lv-chapters {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.lv-chapter {
    display: grid;
    grid-template-columns: 3.25rem minmax(0, 1fr);
    gap: var(--space-3);
    align-items: start;
    min-height: 44px;
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--color-gray-200);
    border-radius: var(--radius-xl);
    color: inherit;
    text-decoration: none;
    transition: border-color var(--duration-fast) var(--ease-out),
                background-color var(--duration-fast) var(--ease-out);
}

.lv-chapter:hover { border-color: var(--color-purple-light); }

.lv-chapter:focus-visible {
    outline: 2px solid var(--color-purple);
    outline-offset: 2px;
}

.lv-chapter[aria-current="true"] {
    border-color: var(--color-purple);
    background: rgba(139, 92, 246, 0.06);
}

.lv-chapter-time {
    font-variant-numeric: tabular-nums;
    font-weight: var(--font-semibold);
    color: var(--color-purple-dark);
}

.lv-chapter-name {
    display: block;
    font-weight: var(--font-semibold);
    color: var(--color-text-primary);
}

.lv-chapter-desc {
    display: block;
    margin-top: 2px;
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
}

.lv-cta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-top: var(--space-6);
}

@media (max-width: 860px) {
    .lv-grid { grid-template-columns: minmax(0, 1fr); gap: var(--space-8); }
}
