/* ============================================================
   Home page scroll choreography

   Two scroll-driven pieces, both fed by home-scroll.js which
   publishes progress on <html> as custom properties:

     --hero-dock  0 → 1   hero video shrinks into a corner card
     --hero-veil  1 → 0   opacity of the hero furniture (donate
                          copy, stats bar, calendar, wash)

   Below the fold the same stats resolve into a numbered impact
   list that reveals row by row.
   ============================================================ */

:root {
    /* The site's cream white, as used by every non-home page in base.html */
    --yem-cream: #FFFEF7;
    --hero-dock: 0;
    --hero-veil: 1;
    --dock-scale: 1;
    --dock-gap: 24px;
    /* Replaced with real pixel values by home-scroll.js on load and resize */
    --dock-w: 240px;
    --dock-h: 150px;
}

@media (max-width: 768px) {
    :root {
        --dock-gap: 14px;
    }
}

/* The document — not the body box — scrolls the homepage.
   base.html gives <body> `height: 100%`, `overflow-y: auto` and
   `overscroll-behavior-y: none`. That makes body a scroll container which,
   at height auto, has nothing to scroll, and overscroll-behavior stops the
   wheel from chaining out to <html>, which is what actually scrolls. The
   result is a page that eats most wheel and touch input. Taking body out of
   the scrolling business entirely fixes it and lets window.scrollY drive
   the choreography below. */
body[data-route="main.index"] {
    height: auto !important;
    overflow: visible !important;
    overscroll-behavior-y: auto !important;
    /* Cream white under everything below the fold, so section gaps and the
       page edges match the impact list rather than flashing white. */
    background-color: var(--yem-cream, #FFFEF7);
}

/* ---------- Layout: reserve the first screen for the hero ---------- */

.home-page-content {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    /* svh = the viewport with the mobile browser chrome showing, so the hero
       never hides part of itself behind the URL bar. */
    min-height: 100svh;
}

/* Holds the first screen open at exactly one viewport so the impact list
   always begins at the fold, on desktop and mobile alike. */
.hero-stage {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100svh;
    position: relative;
}

/* Bottom of the hero on phones: the calendar is pushed to the foot of the
   stage rather than left floating mid-screen with dead footage under it. */
@media (max-width: 768px) {
    .mobile-calendar-section {
        margin-top: auto !important;
    }
}

/* ---------- The video, from full bleed to docked card ---------- */

/* Deep navy stage the shrinking video uncovers. */
.hero-backdrop {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    /* lvh = the viewport with the browser chrome retracted, so nothing shows
       through underneath once the URL bar slides away mid-scroll. */
    height: 100lvh;
    background: linear-gradient(135deg, #0d234b 0%, #1a3a6e 55%, #2c5282 100%);
    /* Opaque by the time the furniture has cleared, so the video shrinks
       against a finished backdrop rather than bare page. */
    opacity: calc(1 - var(--hero-veil));
    z-index: 0;
    pointer-events: none;
}

/* The frame keeps its full-viewport box for the whole journey and is scaled
   toward its bottom-right corner instead — a composited transform, so the
   shrink costs no layout work on any scroll frame.
   --dock-scale (1 -> the card's share of the viewport width), --dock-w and
   --dock-h are published by home-scroll.js. */
.hero-video-frame {
    --video-scale: 1;

    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    /* Sized to the tallest the viewport can get, so the footage still reaches
       the bottom edge on a phone once the URL bar retracts. */
    height: 100lvh;
    transform-origin: 100% 100%;
    transform: translate(calc(-1 * var(--dock-gap) * var(--hero-dock)),
                         calc(-1 * var(--dock-gap) * var(--hero-dock)))
               scale(var(--dock-scale));
    /* Counter-scaled so the corner reads as ~14px however far it has shrunk */
    border-radius: calc(14px * var(--hero-dock) / max(var(--dock-scale), 0.02));
    overflow: hidden;
    z-index: 0;
    pointer-events: none;
    background: #000;
    transition: opacity 0.3s ease;
    will-change: transform;
    backface-visibility: hidden;
}

/* Once it starts shrinking it floats over the page rather than
   sitting behind it. */
body.hero-lifted .hero-video-frame,
body.hero-lifted .video-dock-chrome {
    z-index: 10050;
}

body.video-dismissed .hero-video-frame,
body.video-dismissed .video-dock-chrome {
    opacity: 0;
    pointer-events: none;
}

/* The card parks in the bottom-right corner, which is where the footer keeps
   its Terms and Login links — so it steps aside once the footer is on screen
   rather than swallowing those clicks. */
body.dock-parked .hero-video-frame,
body.dock-parked .video-dock-chrome {
    opacity: 0;
    pointer-events: none;
}

@media (min-width: 769px) {
    .hero-video-frame {
        --video-scale: 1.4;
    }
}

.hero-video-frame .hero-background-video {
    position: absolute !important;
    top: 0 !important;
    left: 0 !important;
    width: 100% !important;
    height: 100% !important;
    object-fit: cover;
    z-index: 0 !important;
    opacity: 1;
    pointer-events: none;
    transform: scale(calc(var(--video-scale) + (1 - var(--video-scale)) * var(--hero-dock))) !important;
    transform-origin: center center;
}

/* Transparent scrim over the footage: heaviest on the left, where the donate
   copy sits, with a light lift top and bottom for the nav and the calendar.
   It clears away as the video shrinks so the docked card plays unfiltered. */
.hero-video-frame .hero-video-veil {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background:
        linear-gradient(to right,
            rgba(6, 14, 30, 0.22) 0%,
            rgba(6, 14, 30, 0.10) 45%,
            rgba(6, 14, 30, 0.02) 100%),
        linear-gradient(to bottom,
            rgba(6, 14, 30, 0.12) 0%,
            rgba(6, 14, 30, 0) 38%,
            rgba(6, 14, 30, 0.18) 100%);
    opacity: calc(1 - var(--hero-dock));
}

@media (max-width: 768px) {
    .hero-video-frame .hero-video-veil {
        background:
            linear-gradient(to bottom,
                rgba(6, 14, 30, 0.16) 0%,
                rgba(6, 14, 30, 0.06) 40%,
                rgba(6, 14, 30, 0.22) 100%);
    }
}

/* Flat brand-blue wash over the footage, tying it to the navy/cream palette
   used across the rest of the site. Sits above the dark veil, and clears
   away as the video docks so the card plays unfiltered. */
.hero-video-frame .hero-blue-overlay {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: rgba(26, 58, 92, 0.38);
    mix-blend-mode: multiply;
    opacity: calc(1 - var(--hero-dock));
}

/* Small soft white highlight sitting near the top of the frame, above the
   dark veil, to lift the footage without washing it out. */
.hero-video-frame .hero-white-overlay {
    position: absolute;
    top: -10%;
    left: 50%;
    width: min(420px, 60%);
    aspect-ratio: 1;
    transform: translateX(-50%);
    z-index: 2;
    pointer-events: none;
    background: radial-gradient(closest-side, rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0) 70%);
    opacity: calc(1 - var(--hero-dock));
}

/* Card chrome — shadow, rim and caption. It sits outside the scaled frame at
   the docked card's final geometry, so nothing here shrinks with the video. */
.video-dock-chrome {
    position: fixed;
    right: var(--dock-gap);
    bottom: var(--dock-gap);
    width: var(--dock-w);
    height: var(--dock-h);
    border-radius: 14px;
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.34),
                inset 0 0 0 1px rgba(255, 255, 255, 0.22);
    opacity: clamp(0, calc((var(--hero-dock) - 0.8) * 5), 1);
    pointer-events: none;
    z-index: 0;
    overflow: hidden;
    transition: opacity 0.3s ease;
}

.video-dock-bar {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 8px 8px 10px;
    background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.75) 100%);
}

body.hero-docked .video-dock-bar {
    pointer-events: auto;
}

/* Parked and dismissed win over docked: same specificity, so these have to
   follow it. Without them the faded-out bar still swallows clicks on whatever
   sits underneath. */
body.dock-parked .video-dock-bar,
body.video-dismissed .video-dock-bar {
    pointer-events: none;
}

body.dock-parked .video-dock-bar button,
body.video-dismissed .video-dock-bar button {
    visibility: hidden;
}

/* Keep the invisible controls out of the tab order until the card is docked */
body:not(.hero-docked) .video-dock-bar button {
    visibility: hidden;
}

.video-dock-expand,
.video-dock-close {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    border: none;
    background: transparent;
    color: #fff;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
    cursor: pointer;
    padding: 4px;
    transition: opacity 0.2s ease, transform 0.2s ease;
}

.video-dock-expand {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.2px;
    text-align: left;
}

.video-dock-expand:hover,
.video-dock-close:hover {
    opacity: 0.8;
}

.video-dock-play {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    flex: 0 0 26px;
    border: 1.5px solid rgba(255, 255, 255, 0.9);
    border-radius: 50%;
    font-size: 0.6rem;
    padding-left: 2px;
}

.video-dock-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.video-dock-close {
    flex: 0 0 auto;
    font-size: 0.85rem;
    opacity: 0.75;
}

/* The card is a scaled-down viewport, so on a phone it stays portrait —
   sized and captioned like a mini player rather than a widescreen thumbnail. */
@media (max-width: 768px) {
    .video-dock-bar {
        padding: 6px;
        gap: 4px;
        justify-content: space-between;
    }

    .video-dock-text {
        display: none;
    }

    .video-dock-expand {
        flex: 0 0 auto;
    }

    .video-dock-play {
        width: 20px;
        height: 20px;
        flex-basis: 20px;
        font-size: 0.5rem;
    }
}

/* ---------- Hero furniture veils out as the video lifts ---------- */

.donate-overlay,
.desktop-calendar-section,
.mobile-calendar-section {
    opacity: var(--hero-veil);
    transition: opacity 0.25s linear;
}

body.hero-lifted .donate-overlay,
body.hero-lifted .desktop-calendar-section,
body.hero-lifted .mobile-calendar-section {
    pointer-events: none;
}

/* ---------- Impact list ---------- */

.impact-section {
    /* Deliberately warmer/creamier than the site-wide --yem-cream (#FFFEF7,
       which reads as near-white) so this section is visibly cream. */
    background: #FDF6E3;
    color: #1f2328;
    padding: clamp(56px, 8vw, 120px) 0 clamp(48px, 7vw, 96px);
    position: relative;
    z-index: 10000;
    /* Rounded where it meets the hero, square at the foot so it still runs
       flush into whatever follows. */
    border-radius: clamp(18px, 4vw, 34px) clamp(18px, 4vw, 34px) 0 0;
}

/* Public pages ship a site-wide 8px gutter, which leaves the impact list
   almost touching the page edge. Pull it back inwards on its own. */
body:not(.login-page) .impact-section > .container {
    padding-left: clamp(20px, 5vw, 72px) !important;
    padding-right: clamp(20px, 5vw, 72px) !important;
}

.impact-header {
    max-width: 720px;
    margin-bottom: clamp(32px, 4vw, 56px);
}

.impact-eyebrow {
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 2.4px;
    text-transform: uppercase;
    color: var(--yem-navy-deep, #12293f);
    margin-bottom: 12px;
}

.impact-heading {
    color: var(--yem-navy-deep, #12293f);
    font-size: clamp(1.5rem, 2.6vw, 2.3rem);
    font-weight: 700;
    line-height: 1.18;
    letter-spacing: -0.5px;
    margin-bottom: 14px;
}

/* The one place the site steps off Inter: a display grotesque on the section
   title (the webfont is loaded in index.html). Both typography.css and the
   home page's own font block pin every element to Inter with !important, and
   the home page rule is `body .home-page-content h2`, so the override has to
   out-specify it as well as carry !important. */
body .home-page-content .impact-heading {
    font-family: 'Space Grotesk', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
}

.impact-intro {
    font-size: clamp(0.95rem, 1.2vw, 1.08rem);
    line-height: 1.7;
    color: rgba(31, 35, 40, 0.7);
    margin-bottom: 0;
}

.impact-list {
    border-top: 1px solid rgba(31, 35, 40, 0.18);
}

.impact-row {
    display: grid;
    grid-template-columns: minmax(110px, 0.8fr) minmax(200px, 1.3fr) minmax(0, 3fr);
    align-items: start;
    gap: 12px 40px;
    padding: clamp(26px, 3.2vw, 42px) 0;
    border-bottom: 1px solid rgba(31, 35, 40, 0.18);
    transition: opacity 0.65s cubic-bezier(0.22, 0.61, 0.36, 1),
                transform 0.65s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Rows only start hidden once the reveal script has taken charge of them,
   so the list still reads with JavaScript turned off. */
body.impact-reveal .impact-row:not(.is-visible) {
    opacity: 0;
    transform: translateY(26px);
}

.impact-value {
    font-size: clamp(1.9rem, 3vw, 2.9rem);
    font-weight: 800;
    line-height: 1;
    letter-spacing: -1.5px;
    display: flex;
    align-items: baseline;
}

.impact-value .impact-affix {
    font-size: 0.55em;
    font-weight: 700;
    letter-spacing: 0;
}

.impact-name {
    font-size: clamp(1.15rem, 1.9vw, 1.8rem);
    font-weight: 800;
    line-height: 1.2;
    margin: 0;
}

.impact-desc {
    font-size: clamp(0.92rem, 1.1vw, 1.05rem);
    line-height: 1.7;
    color: rgba(31, 35, 40, 0.72);
    /* Runs out to the grid column so the row fills its width; the cap only
       bites on very wide monitors, to keep lines readable. */
    max-width: 78ch;
    margin: 0;
}

.impact-cta {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    margin-top: clamp(32px, 4vw, 52px);
    padding: 14px 28px;
    border-radius: 999px;
    background: var(--yem-navy-soft, #24507f);
    color: #fff;
    font-weight: 700;
    font-size: 0.9rem;
    text-decoration: none;
    transition: background 0.25s ease, transform 0.25s ease;
}

.impact-cta:hover {
    background: #2d6099;
    color: #fff;
    transform: translateY(-2px);
}

@media (max-width: 767.98px) {
    .impact-row {
        grid-template-columns: auto minmax(0, 1fr);
        gap: 8px 16px;
    }

    .impact-value {
        grid-row: 1;
    }

    .impact-name {
        grid-row: 1;
        align-self: center;
    }

    .impact-desc {
        grid-column: 1 / -1;
    }
}

@media (prefers-reduced-motion: reduce) {
    body.impact-reveal .impact-row:not(.is-visible) {
        opacity: 1;
        transform: none;
    }

    .impact-row {
        transition: none;
    }

    .hero-video-frame,
    .impact-cta {
        transition: none;
    }
}
