/* Motion for the public pages (owner, 2026-10-17: "bold ... bounce ... make
   the website LIVE ... animations and proper transitions everywhere").

   One spring for everything that settles: it overshoots about 5% and comes
   to rest, the way the app's sheets do (layout.css --otf-motion-spring). It
   runs on transform and opacity only, so the compositor draws it, and none of
   it runs under Reduce Motion, where every state is immediate. The repeating
   parts (a live dot's ring) are small leaves and pause off screen with their
   section.

   scripts/motion.js adds the parts CSS cannot: numbers that count up the
   first time they are seen, and countdowns that tick when they change. */

.otf-public-home {
    --otf-spring: linear(0, 0.068, 0.2232, 0.4094, 0.5902, 0.7454, 0.8666, 0.9531, 1.0087, 1.0397, 1.0526, 1.0535, 1.0474, 1.0379, 1.0278, 1.0185, 1.0108, 1.005, 1.0011, 0.9987, 0.9974, 1);
    --otf-spring-dur: 720ms;
    --otf-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
}

@media (prefers-reduced-motion: no-preference) {
    /* Seen for the first time: rises and settles with the spring, a little
       further and a little larger than before, one after another. */
    .otf-public-home.otf-public-home [data-otf-reveal].otf-in {
        animation: otfRiseSettle var(--otf-spring-dur) var(--otf-spring) backwards;
        animation-delay: calc(min(var(--otf-reveal-i, 0), 6) * 75ms);
    }

    @keyframes otfRiseSettle {
        from { opacity: 0; transform: translateY(28px) scale(0.975); }
        40% { opacity: 1; }
        to { opacity: 1; transform: none; }
    }

    /* Headings come in word by word (scripts/motion.js splits them): each
       word rises from under the line, sharpens and settles on the spring,
       38ms after the one before. Until its heading is seen, a word waits
       hidden. */
    .otf-public-home .otf-w {
        display: inline-block;
    }

    .otf-public-home [data-otf-words]:not(.otf-words-in) .otf-w {
        opacity: 0;
    }

    .otf-public-home .otf-words-in .otf-w {
        animation: otfWordIn 640ms var(--otf-spring) backwards;
        animation-delay: calc(var(--w, 0) * 38ms + 60ms);
    }

    @keyframes otfWordIn {
        from { opacity: 0; transform: translateY(0.42em); filter: blur(4px); }
        to { opacity: 1; transform: none; filter: blur(0); }
    }

    /* Pressing gives way at once; letting go springs back past rest. */
    .otf-public-home :is(.otf-public-button, .otf-glass-button, .otf-explore-chip, .otf-live-refresh,
        .otf-live-retry, .otf-fp-more-link, .otf-fp-links a, .otf-public-nav-link, .otf-public-text-button, .otf-nav-toggle) {
        transition-property: transform, background-color, border-color, color, box-shadow;
        transition-duration: var(--otf-spring-dur), 200ms, 200ms, 200ms, 240ms;
        transition-timing-function: var(--otf-spring), ease, ease, ease, ease;
    }

    .otf-public-home :is(.otf-public-button, .otf-glass-button, .otf-explore-chip, .otf-live-refresh,
        .otf-live-retry, .otf-fp-more-link, .otf-fp-links a, .otf-public-text-button, .otf-nav-toggle):active {
        transform: scale(0.96);
        transition-duration: 90ms, 200ms, 200ms, 200ms, 240ms;
        transition-timing-function: ease-out, ease, ease, ease, ease;
    }

    .otf-public-home :is(.otf-public-button, .otf-glass-button.primary):hover {
        transform: translateY(-3px) scale(1.03);
    }

    /* Cards lift on the same spring and land back on it. */
    .otf-public-home :is(.otf-public-feature, .otf-fp-card, .otf-live-card, .otf-upcoming-card, .otf-public-preview-card) {
        transition: transform var(--otf-spring-dur) var(--otf-spring), box-shadow 320ms ease, border-color 320ms ease;
    }

    .otf-public-home :is(.otf-fp-card, .otf-live-card, .otf-upcoming-card):hover {
        transform: translateY(-6px);
        box-shadow: 0 26px 60px var(--otf-public-shadow);
        border-color: color-mix(in srgb, var(--otf-public-ivory) 34%, transparent);
    }

    .otf-public-home .otf-fp-card:hover .otf-fp-card-icon,
    .otf-public-home .otf-public-feature:hover > span {
        transform: translateY(-3px) rotate(-6deg) scale(1.08);
    }

    .otf-public-home :is(.otf-fp-card-icon, .otf-public-feature > span, .otf-live-icon, .otf-fp-fact-icon) {
        transition: transform var(--otf-spring-dur) var(--otf-spring);
    }

    /* A chip that becomes the current choice pops. */
    .otf-public-home .otf-explore-chip[aria-pressed="true"] {
        animation: otfChipPop 520ms var(--otf-spring);
    }

    @keyframes otfChipPop {
        from { transform: scale(0.9); }
        to { transform: none; }
    }

    /* Live: the dot in a live section's eyebrow, and every "Live" time,
       breathes a ring outward. */
    .otf-public-home :is(.otf-live, .otf-tone-green) .otf-public-eyebrow > span,
    .otf-public-home .otf-live-status.is-normal .otf-live-status-dot {
        position: relative;
    }

    .otf-public-home .otf-live-row-time small.is-live::before {
        animation: otfBreathe 1.8s ease-in-out infinite;
    }

    @keyframes otfBreathe {
        50% { opacity: 0.35; transform: scale(0.7); }
    }

    .otf-public-home :is(.otf-live, .otf-tone-green) .otf-public-eyebrow > span::after,
    .otf-public-home .otf-live-status.is-normal .otf-live-status-dot::after {
        content: "";
        position: absolute;
        inset: 0;
        border-radius: 50%;
        background: currentColor;
        color: var(--otf-public-live);
        animation: otfLivePing 2.2s var(--otf-ease-out) infinite;
    }

    @keyframes otfLivePing {
        from { opacity: 0.7; transform: scale(1); }
        70%, to { opacity: 0; transform: scale(3.2); }
    }

    /* Off screen, the loops hold still (scripts/motion.js marks the section). */
    .otf-public-home .otf-offscreen .otf-live-row-time small.is-live::before,
    .otf-public-home .otf-offscreen .otf-public-eyebrow > span::after,
    .otf-public-home .otf-offscreen .otf-live-status.is-normal .otf-live-status-dot::after,
    .otf-public-home .otf-offscreen .otf-demo-spot > span {
        animation-play-state: paused;
    }

    /* A live panel's first answer comes in row by row. */
    .otf-public-home .otf-live-body.is-entering > * > li,
    .otf-public-home .otf-live-body.is-entering > :is(.otf-live-weather, .otf-live-status, .otf-live-lede) {
        animation: otfRiseSettle 640ms var(--otf-spring) backwards;
    }

    .otf-public-home .otf-live-body.is-entering > * > li:nth-child(2) { animation-delay: 60ms; }
    .otf-public-home .otf-live-body.is-entering > * > li:nth-child(3) { animation-delay: 120ms; }
    .otf-public-home .otf-live-body.is-entering > * > li:nth-child(4) { animation-delay: 180ms; }
    .otf-public-home .otf-live-body.is-entering > * > li:nth-child(n + 5) { animation-delay: 240ms; }

    /* A countdown that moves ticks: the new figure drops in from above. */
    .otf-public-home .is-ticking {
        display: inline-block;
        animation: otfTick 420ms var(--otf-spring);
    }

    @keyframes otfTick {
        from { opacity: 0; transform: translateY(-0.45em); }
        to { opacity: 1; transform: none; }
    }

    /* Page changes: the old page steps back and is gone in 160ms, and the
       new one rises in on the spring from 100ms, so the two pages' words
       never sit over each other (both fading at once showed one title
       through the other). */
    ::view-transition-old(root) {
        animation: 160ms cubic-bezier(0.22, 1, 0.36, 1) both otfPageOut;
    }

    ::view-transition-new(root) {
        animation: 560ms linear(0, 0.068, 0.2232, 0.4094, 0.5902, 0.7454, 0.8666, 0.9531, 1.0087, 1.0397, 1.0526, 1.0535, 1.0474, 1.0379, 1.0278, 1.0185, 1.0108, 1.005, 1.0011, 0.9987, 0.9974, 1) 100ms both otfPageIn;
    }

    @keyframes otfPageOut {
        to { opacity: 0; transform: scale(0.985); }
    }

    @keyframes otfPageIn {
        from { opacity: 0; transform: translateY(22px); }
    }
}

/* Bold type: section headings carry more weight, and the ivory band's
   numbers are Cardinal red, the one place they are. */
.otf-public-home :is(.otf-public-section-head h2, .otf-fp-copy h2, .otf-public-split h2, .otf-public-safety h2, .public-home-faq h2) {
    font-weight: 820;
    letter-spacing: -0.035em;
}

.otf-public-home .otf-subpage-hero h1 {
    font-weight: 840;
    letter-spacing: -0.04em;
}

.otf-public-home .otf-tone-light .public-home-stat-value {
    color: #8c1515;
    font-weight: 860;
    letter-spacing: -0.04em;
}

.otf-public-home .otf-public-eyebrow {
    letter-spacing: 0.14em;
}

/* Counting numbers keep their width while they climb. */
.otf-public-home [data-count-value] {
    font-variant-numeric: tabular-nums;
}

/* Type and surface details (make-interfaces-feel-better): crisp type on
   macOS, balanced headings and no orphan words in body copy, and a faint
   white edge on photographs so each one sits on the page the same way. */
.otf-public-home {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

.otf-public-home :is(h1, h2, h3) { text-wrap: balance; }

.otf-public-home :is(.otf-public-section-head > p, .otf-fp-lede, .otf-public-feature p, .otf-fp-facts p,
    .otf-source > p, .otf-subpage-lede, .otf-live-empty, .public-home-faq .otf-faq-answer) {
    text-wrap: pretty;
}

.otf-public-home :is(.otf-upcoming-photo img, .otf-about-photo) {
    outline: 1px solid oklch(1 0 0 / 0.1);
    outline-offset: -1px;
}

/* Small text links get a 24px tall target (WCAG 2.5.8) without changing how
   they look: photo credits, a notice's link and a source's name. Every link
   and button shows where keyboard focus is. */
/* (The footer's lists already have 44px rows; this rule once shrank them.) */
.otf-public-home :is(.otf-live-note > a, .otf-source-head a, .otf-cinema-credit a, .otf-upcoming-photo figcaption a,
    .otf-mask-credit a, .public-home-photo-credits a) {
    display: inline-flex;
    align-items: center;
    min-height: 24px;
}

.otf-public-home :is(a, button):focus-visible {
    outline: 2px solid var(--otf-public-sand);
    outline-offset: 3px;
}
