body {
    margin: 0;
    padding: 72px 3em 48px;

    background-color: #fff;
    font-family: 'Open Sans', sans-serif;
    color: #333;
    font-size: 12px;
    line-height: 20px;
}

a:link,
a:visited {
    color: #333;
}

.section {
    display: block;
    max-width: 850px;
    margin: 0 auto;
}

/* ------------------------------------------------------ */
/* Header: title, subtitle, authors, affiliations         */
/* ------------------------------------------------------ */

header {
    text-align: center;
}

.title {
    margin: 0;
    font-family: 'Varela Round', sans-serif;
    color: #4d4d4d;
    font-size: 50px;
    line-height: 65px;
    font-weight: 700;
}

.subheader {
    margin: 0 0 6px;
    color: #333;
    font-size: 25px;
    line-height: 44px;
    font-weight: 500;
}

/* Each half of the subtitle stays on one line; the break falls between them. */
.subheader span {
    display: inline-block;
}

.authors {
    max-width: 850px;
    margin: 0 auto;
    font-size: 16px;
    line-height: 26px;
    text-wrap: balance;
}

.author {
    display: inline-block;
    white-space: nowrap;
    margin: 0 0.6em;
}

.text-star {
    position: relative;
    top: -7px;
    margin-left: 1px;
    font-size: 10px;
}

/* Gray affiliation row under the author list, following https://hongsukchoi.github.io/fpo-control/ */
.affiliations {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.2em 0.875em;
    white-space: nowrap;
    font-style: italic;
    font-size: 0.9rem;
    opacity: 0.5;
    margin-top: 4px;
}

.affiliations .text-star {
    top: -5px;
    margin-right: 1px;
}

/* ------------------------------------------------------ */
/* Paper / code links                                     */
/* ------------------------------------------------------ */

.links {
    margin-top: 16px;
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.75em;
}

.button,
.button:link,
.button:visited {
    display: inline-flex;
    align-items: center;
    gap: 0.35em;
    padding: 0.5em 1.1em;
    border-radius: 0.2rem;
    background-color: #333;
    color: #fff;
    font-size: 14px;
    font-weight: 600;
    text-decoration: none;
}

.button:hover {
    background-color: #555;
}

/* A link that isn't out yet: no href, greyed out. */
.button.disabled,
.button.disabled:hover {
    background-color: #ccc;
    cursor: default;
}

/* Hover (or tap) note on a link that isn't out yet: a speech bubble beside the button, so it covers nothing. */
.button.has-tip {
    position: relative;
}

.button.has-tip .tip,
.button.has-tip::before {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.15s;
    z-index: 10;
}

/* The bubble: one phrase per line, so it's exactly as wide as the longer one. */
.button.has-tip .tip {
    left: calc(100% + 10px);
    width: max-content;
    padding: 0.35em 0.75em;
    border-radius: 0.6rem;
    background-color: #f1f1f1;
    color: #555;
    font-size: 13px;
    font-weight: 400;
    text-align: left;
}

.button.has-tip .tip span {
    display: block;
    white-space: nowrap;
}

/* Its tail, pointing back at the button. */
.button.has-tip::before {
    content: "";
    left: calc(100% + 4px);
    border: 6px solid transparent;
    border-left: 0;
    border-right-color: #f1f1f1;
}

.button.has-tip:hover .tip,
.button.has-tip:hover::before,
.button.has-tip:focus-visible .tip,
.button.has-tip:focus-visible::before {
    opacity: 1;
}

/* Too narrow to sit beside the button: drop below it. */
@media screen and (max-width: 640px) {
    .button.has-tip .tip {
        top: calc(100% + 10px);
        left: 50%;
        transform: translateX(-50%);
        text-align: center;
    }

    .button.has-tip::before {
        top: calc(100% + 4px);
        left: 50%;
        transform: translateX(-50%);
        border: 6px solid transparent;
        border-top: 0;
        border-bottom-color: #f1f1f1;
    }
}

/* ------------------------------------------------------ */
/* Body text                                              */
/* ------------------------------------------------------ */

.paragraph {
    margin: 0;
    color: #333;
    font-size: 16px;
    line-height: 24px;
    font-weight: 400;
    text-align: left;
}

.tldr {
    margin: 40px 0 12px;
    color: #333;
    font-size: 18px;
    line-height: 24px;
    font-weight: 450;
    text-align: center;
    text-wrap: balance;
}

.section-title {
    margin: 0 0 20px;
    font-size: 24px;
    line-height: 32px;
    font-weight: 700;
    text-align: center;
}

/* A split title's halves stay whole, so it only breaks between them. */
.section-title span {
    display: inline-block;
}

/* A thin filmstrip of results under the TL;DR (filmstrip.js), about a third of the old teaser's height, cut clean at the
   column's edges. Every tile is 4:3 (cropped to fill), so the strip reads as one even row. A sideways drag or swipe
   scrolls it (vertical swipes still scroll the page). */
.filmstrip {
    height: 160px;
    margin-bottom: 10px;
    overflow: hidden;
    border-radius: 10px;
    touch-action: pan-y;
    -webkit-user-select: none;
    user-select: none;
}

.filmstrip-track {
    display: flex;
    gap: 8px;
    height: 100%;
    will-change: transform;
}

.filmstrip video {
    flex: none;
    height: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    border-radius: 10px;
    background: #f0f0f0;
    cursor: zoom-in;
}

.filmstrip.dragging video {
    cursor: grabbing;
}

/* With reduced motion it holds still, and scrolls by hand. */
.filmstrip.still {
    overflow-x: auto;
    touch-action: auto;
}

/* ------------------------------------------------------ */
/* Results carousels, following https://hongsukchoi.github.io/fpo-control/ */
/* ------------------------------------------------------ */

.results-row + .results-row {
    margin-top: 40px;
}

.row-caption {
    font-size: 22px;
    line-height: 30px;
    font-weight: 600;
    text-align: center;
}

.row-subcaption {
    margin-top: 2px;
    margin-bottom: 6px;
    color: #888;
    font-size: 15px;
    line-height: 20px;
    text-align: center;
}

/* Text on the left, learning curves (results-plots.js) on the right, above each row's videos. */
.results-summary {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 40px;
    align-items: center;
    margin: 16px 0 12px;
}

/* Stand-in text for a result that isn't in yet. */
.placeholder-text {
    color: #999;
    font-style: italic;
}

.results-figure {
    margin: 0;
}

/* A row with no plot: text spans the full width. */
.results-summary.text-only {
    grid-template-columns: minmax(0, 1fr);
}

/* Label under a single carousel, styled like .row-subcaption. */
.carousel-caption {
    margin-bottom: 12px;
    color: #888;
    font-size: 15px;
    line-height: 20px;
    text-align: center;
}

/* A small second line under a caption, for a sampling detail. */
.caption-note {
    display: block;
    margin-top: 2px;
    color: #aaa;
    font-size: 13px;
    line-height: 18px;
}

.carousel-caption a:link,
.carousel-caption a:visited {
    color: inherit;
}

.results-plot {
    display: block;
    width: 100%;
    height: auto;
    font-family: inherit;
}

.slider-wrapper {
    position: relative;
}

.video-slider {
    display: flex;
    gap: 15px;
    padding: 10px 0;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
}

.video-slider::-webkit-scrollbar {
    display: none;
}

/* Three videos per view. */
.video-slider > * {
    flex: 0 0 calc((100% - 2 * 15px) / 3);
    min-width: 0;
    scroll-snap-align: start;
}

.video-slider video {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3; /* held before the clip loads (preload="none"), so the page doesn't shift */
    border-radius: 8px;
    cursor: pointer;
}

.video-slider.prompts video {
    aspect-ratio: 1;
}

.video-slider video:hover {
    outline: 3px solid #4dacff;
    outline-offset: -3px;
}

/* Stand-in for a result video that isn't ready yet; 4:3 like the manipulation clips. */
.video-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 4 / 3;
    border: 2px dashed #ccc;
    border-radius: 8px;
    background-color: #f4f4f4;
    padding: 8px;
    color: #999;
    font-size: 14px;
    line-height: 20px;
    text-align: center;
}

/* Image samples are square. */
.video-placeholder.square {
    aspect-ratio: 1 / 1;
}

/* Prompt captions under the image samples. */
.video-slider.prompts figcaption {
    font-style: italic;
}

.video-slider figure {
    margin: 0;
}

/* Base vs. QF3 clips, the two tasks side by side. */
.race-pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 15px;
    padding: 10px 0;
}

.race-pair figure {
    margin: 0;
    min-width: 0;
}

.race-pair video {
    display: block;
    width: 100%;
    border-radius: 8px;
    cursor: pointer;
}

.race-pair video:hover {
    outline: 3px solid #4dacff;
    outline-offset: -3px;
}

.race-pair figcaption {
    margin-top: 4px;
    color: #888;
    font-size: 13px;
    line-height: 18px;
    text-align: center;
}

/* Base vs. QF3 on one seed, in sync (manip-race.js), in the figures' dotted box (.rw) with their tabs (.rw-tabs),
   play button (.cq-play). Base is the plots' grey, QF3 their blue.
   One set of corners: 8px for the videos and the timeline panel, 4px for the chips, 2px for the bars. */
.mr {
    --mr-base: #999;
    --mr-qf3: #2a6f97;
    --mr-ink: #374151;
    --mr-muted: #8a8a8a;
    --mr-line: #dedede;
    --mr-panel: #f5f5f5; /* the timeline panel's fill; the faint grasps and dots are mixed toward it */
    margin: 12px 0 10px;
}

.mr-t-base {
    --mr-c: var(--mr-base);
}

.mr-t-qf3 {
    --mr-c: var(--mr-qf3);
}

/* Top row: the task tabs on the left, play/pause and speed on the right. */
.mr-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 10px 12px;
    margin-bottom: 10px;
}

.mr-tab[aria-selected="true"] {
    border-color: #333;
    background: #333;
    color: #fff;
}

.mr-controls {
    display: flex;
    align-items: center;
    gap: 6px;
}

/* Centered by flexbox rather than .cq-play's line-height (the icon font's box sits off-center); the play triangle
   gets a 1px nudge right, since it looks left-heavy when centered exactly. */
.mr-play {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    font-size: 12px;
    line-height: 1;
}

.mr-play .ti-player-play {
    transform: translateX(1px);
}

.mr-rates {
    display: flex;
}

.mr-rates button {
    padding: 0 4px;
    border: none;
    background: none;
    color: #aaa;
    font: 600 12px/22px 'Open Sans', sans-serif;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
}

.mr-rates button:hover,
.mr-rates button[aria-pressed="true"] {
    color: var(--mr-ink);
}

.mr-rates button[aria-pressed="true"] {
    text-decoration: underline;
    text-decoration-thickness: 1.5px;
    text-underline-offset: 3px;
}

/* The two videos, cropped from square to 4:3 like the old race clips: 10% of the empty back wall off the top and 15%
   of the rail off the bottom (the arms and objects stay inside it in every frame of all four clips). */
.mr-pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
}

.mr-side {
    position: relative;
    min-width: 0;
}

.mr-side video {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    object-position: 50% 40%;
    border-radius: 8px;
    background: #f4f3ef;
    transition: opacity 0.3s;
}

/* On each video: the policy and its episode clock (which stops when the episode ends) at top left, the playback
   speed at top right. */
.mr-chip {
    position: absolute;
    top: 8px;
    padding: 1px 7px;
    border-radius: 4px;
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    font-size: 13px;
    line-height: 20px;
    font-weight: 600;
    white-space: nowrap;
    pointer-events: none;
}

.mr-label {
    left: 8px;
}

.mr-rate {
    right: 8px;
    font-weight: 400;
}

.mr-len {
    margin-left: 4px;
    font-weight: 400;
    font-variant-numeric: tabular-nums;
    opacity: 0.85;
}

/* The faster episode, once done: dimmed under a check, as in the old race clips. */
.mr-check {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 20%;
    transform: translate(-50%, -50%);
    display: none;
    filter: drop-shadow(0 4px 3px rgba(0, 0, 0, 0.1));
}

.mr-side.won video {
    opacity: 0.4;
}

.mr-side.won .mr-check {
    display: block;
}

/* The timeline panel: per policy a heading, a row per arm and a row of counted items, every row the same height;
   a hairline between the policies; the time axis at the bottom. manip-race.js sets the rows. */
.mr-panel {
    margin: 10px 0 0;
    padding: 8px 16px 4px;
    border-radius: 8px;
    background: var(--mr-panel);
}

.mr-tl {
    --end: 9px; /* room for a dot at the very end */
    display: grid;
    grid-template-columns: 92px 1fr;
    align-items: center;
    row-gap: 3px;
    padding-right: var(--end);
    user-select: none;
}

.mr-heading {
    display: flex;
    align-items: center;
    gap: 7px;
    color: var(--mr-ink);
    font-size: 13px;
    line-height: 18px;
    font-weight: 600;
}

/* A short bar in the policy's color, the shape of the grasps it keys. */
.mr-swatch {
    width: 14px;
    height: 6px;
    border-radius: 2px;
    background: var(--mr-c);
}

.mr-rule {
    height: 1px;
    background: var(--mr-line);
}

.mr-hand {
    color: var(--mr-muted);
    font-size: 12px;
    line-height: 14px;
}

.mr-track {
    position: relative;
    height: 8px;
    cursor: pointer;
}

.mr-track.mr-items {
    height: 16px;
}

/* An arm's row: a 1px baseline as long as its episode, so the faster policy's rows visibly end sooner. */
.mr-span {
    position: absolute;
    top: 50%;
    left: 0;
    height: 1px;
    background: var(--mr-line);
}

/* A grasp: faint in the policy's color until played, filling solid as the clip plays through it. The fill grows by
   transform, not width, so its edge glides instead of re-rasterizing each frame. */
.mr-grasp {
    position: absolute;
    top: 0;
    bottom: 0;
    min-width: 2px;
    border-radius: 2px;
    background: color-mix(in srgb, var(--mr-c) 25%, var(--mr-panel));
    overflow: hidden;
    isolation: isolate; /* keeps Safari clipping the scaled fill to the rounded corners */
}

.mr-grasp-fill {
    height: 100%;
    background: var(--mr-c);
    transform: scaleX(0);
    transform-origin: 0 0;
    will-change: transform;
}

/* A counted item: a small dot until the eval counts it, then a numbered circle like .cq-num. */
.mr-dot {
    position: absolute;
    top: 0;
    z-index: 1;
    width: 16px;
    height: 16px;
    margin-left: -8px;
    padding: 0;
    border: none;
    border-radius: 8px;
    background: color-mix(in srgb, var(--mr-c) 35%, var(--mr-panel));
    color: transparent;
    font: 700 10px/16px 'Open Sans', sans-serif;
    text-align: center;
    cursor: pointer;
    transform: scale(0.4);
    transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), background 0.2s, color 0.2s;
}

.mr-dot:hover {
    transform: scale(0.5);
}

.mr-dot.on {
    background: var(--mr-c);
    color: #fff;
    transform: scale(1);
}

.mr-axis {
    position: relative;
    height: 17px;
    margin-top: 3px;
    border-top: 1px solid var(--mr-line);
}

.mr-axis span {
    position: absolute;
    top: 3px;
    transform: translateX(-50%);
    color: #999;
    font-size: 11px;
    line-height: 14px;
    font-variant-numeric: tabular-nums;
}

.video-slider figcaption {
    margin-top: 4px;
    color: #888;
    font-size: 13px;
    line-height: 18px;
    text-align: center;
}

.slider-btn {
    position: absolute;
    top: 50%;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(51, 51, 51, 0.8);
    color: #fff;
    font-size: 20px;
    cursor: pointer;
    transform: translateY(-50%);
}

.slider-btn:hover {
    background: #333;
}

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

.slider-btn.prev {
    left: 10px;
}

.slider-btn.next {
    right: 10px;
}

.video-modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: none;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.7);
    backdrop-filter: blur(4px);
}

.video-modal-overlay.active {
    display: flex;
}

.video-modal {
    position: relative;
}

.video-modal video {
    display: block;
    max-width: 90vw;
    max-height: 90vh;
    border-radius: 10px;
}

.video-modal-close {
    position: absolute;
    top: 10px;
    right: 10px;
    width: 32px;
    height: 32px;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.6);
    color: #fff;
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
}

.video-modal-close:hover {
    background: rgba(0, 0, 0, 0.9);
}

/* ------------------------------------------------------ */
/* Where QF3 fits: click-through 1D plot (related-figure.js) */
/* ------------------------------------------------------ */

.rw {
    padding: 14px 16px 16px;
    border: 2px dotted #d4d4d4;
    border-radius: 15px;
}

/* Prior work, collapsed under QF3's figure into one outlined box that expands in place. */
.rw-prior {
    margin-top: 12px;
}

.rw-panel {
    box-sizing: border-box;
    margin-top: 10px;
}

/* QF3's clipping figure (slide 12), stepped through with a slider (clipped-q.js). */
.cq-figure {
    aspect-ratio: 1240 / 445;
}

.cq-figure > svg {
    display: block;
    width: 100%;
    height: 100%;
}

/* The generated SVG pins opacity inline, hence !important. clipped-q.js hides the elements of later steps. */
.cq-svg > * {
    transition: opacity 0.6s ease-out !important;
}

.cq .cq-off {
    opacity: 0 !important;
}

/* The last step (the critic gradients) keeps its data-keep elements (x_tau, v_theta, the replay action, x-hat_1,clip, Q(a)),
   fades the axes, and hides the rest. */
.cq.cq-focus .cq-svg > :not([data-step]):not([data-keep]) {
    opacity: 0.3 !important;
}

.cq.cq-focus .cq-svg > [data-step]:not([data-step="6"]):not([data-keep]) {
    opacity: 0 !important;
}

/* The step caption, with play/pause at the right. */
.cq-head {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 6px 4.4% 0;
}

/* All captions share one cell, so the block keeps the tallest one's height as they swap. */
.cq-captions {
    display: grid;
    flex: 1;
    min-width: 0; /* a long formula can't push the play button out of the box */
}

.cq-caption {
    grid-area: 1 / 1;
    margin: 0;
    color: #374151;
    font-size: 14px;
    line-height: 22px;
    font-weight: 500;
}

/* Each caption's formula sits on its own line, under the text after the step number. */
.cq-eq {
    display: block;
    padding-left: 24px;
    color: #6b7280; /* lighter than the sentence, so the text leads */
}

.cq-caption[hidden] {
    display: block;
    visibility: hidden;
}

.cq-num {
    display: inline-block;
    width: 18px;
    height: 18px;
    margin: 2px 6px 0 0; /* centered on the first 22px line */
    vertical-align: top;
    border-radius: 9px;
    background: #2a6f97;
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    line-height: 18px;
    text-align: center;
}

/* The clip figure's scrubber: the slideshow's (.in-play, .in-track, .in-seg, .in-knob), one segment per step. */
.cq-scrub {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 12px;
    align-items: center;
    margin: 8px 4.4% 0;
}

.cq-segs {
    display: flex;
    flex: 1;
    gap: 3px;
}

.cq-segs > .in-seg {
    flex: 1 1 0;
}

.cq-play {
    flex: none;
    width: 26px;
    height: 26px;
    padding: 0;
    border: 1px solid #d8d6cf;
    border-radius: 50%;
    background: #fff;
    color: #2a6f97;
    font-size: 13px;
    line-height: 24px;
    cursor: pointer;
}

.cq-play:hover {
    border-color: #2a6f97;
}

/* A thin outlined box; its bar (the question and a chevron) tints on hover, so it reads as clickable. */
.rw-compare {
    border: 1px solid #e4e2dc;
    border-radius: 10px;
    transition: border-color 0.2s;
}

.rw-compare:has(> summary:hover) {
    border-color: #ccc;
}

/* The panel opens inside the box, so it drops the figures' own dotted outline. */
.rw-compare > .rw-panel {
    margin-top: 0;
    padding-top: 4px;
    border: none;
}

.rw-compare > summary {
    display: flex;
    flex-wrap: nowrap; /* the chevron stays on the question's line; the question wraps on its own */
    align-items: center;
    gap: 8px 14px;
    padding: 11px 16px;
    border-radius: 9px;
    list-style: none;
    color: #333;
    font-size: 16px;
    line-height: 24px;
    font-weight: 600;
    cursor: pointer;
    transition: color 0.2s, background 0.2s;
}

.rw-compare > summary > span {
    flex: 1;
    min-width: 0;
}

.rw-compare > summary::-webkit-details-marker {
    display: none;
}

.rw-compare > summary:hover {
    color: #2a6f97;
    background: #f7f7f7;
}

/* Open, the tint stops at the bar's bottom edge, so only the top corners round. */
.rw-compare[open]:not(.closing) > summary {
    border-radius: 9px 9px 0 0;
}

.rw-compare > summary .ti {
    margin-left: auto;
    color: #999;
    font-size: 20px;
    transition: transform 0.35s ease-in-out;
}

/* related-figure.js marks a closing block, so the chevron turns back as the panel starts to collapse. */
.rw-compare[open]:not(.closing) > summary .ti {
    transform: rotate(180deg);
}

.rw-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.rw-tabs button {
    padding: 4px 14px;
    border: 1px solid #ccc;
    border-radius: 6px;
    background: #fff;
    color: #333;
    font: 600 14px/20px 'Open Sans', sans-serif;
    cursor: pointer;
}

.rw-tabs button:hover {
    border-color: #333;
}

.rw-tabs button[aria-pressed="true"] {
    border-color: #333;
    background: #333;
    color: #fff;
}

/* Plot and explanation, 2:1. */
/* Inline KaTeX, sized to the surrounding text. */
.m .katex {
    font-size: 1.08em;
    white-space: nowrap;
}

.rw-body {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: 20px;
    align-items: center;
    margin-top: 12px;
}

.rw-plot {
    display: block;
    width: 100%;
    height: auto;
    font-family: 'STIX Two Text', serif;
}

.rw-title {
    display: flex;
    flex-direction: column;
    font-size: 18px;
    line-height: 24px;
    font-weight: 700;
}

.rw-name {
    display: flex;
    align-items: center;
    gap: 10px;
}

.rw-text p {
    margin: 8px 0 0;
    font-size: 14px;
    line-height: 21px;
}

/* Keep sub/superscripts from spreading the lines apart. */
.rw-text sub,
.rw-text sup {
    line-height: 0;
}

.nw {
    white-space: nowrap;
}

.rw-name a {
    color: #888;
    font-size: 13px;
    font-weight: 400;
    white-space: nowrap;
}

.rw-name a:hover {
    color: #333;
}

.rw-text .rw-vs {
    margin-top: 10px;
    padding-top: 8px;
    border-top: 1px solid #eee;
    color: #555;
    font-size: 13px;
    line-height: 20px;
}

.rw-loss {
    margin-top: 10px;
    overflow-x: auto;
    overflow-y: hidden;
    color: #444;
    font-size: 13px;
}

.rw-loss .katex-display {
    margin: 0;
    text-align: left;
}

.rw-loss .katex-display > .katex {
    text-align: left;
}

/* The method's intuition, up front: the teaser's explainer, played live (intuition.js), in six beats, in the figures'
   dotted box. Above the stage, the beat's headline and line, between the back and forward arrows; under it, the
   story's three parts, the current one dark, with a dot per beat under each (the current beat's dark). */
.intuition {
    padding: 16px 18px 14px;
}

.in-head {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    gap: 12px;
    align-items: center;
}

.in-prev,
.in-next {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid #e6e6e6;
    border-radius: 8px;
    background: #fff;
    color: #6b7280;
    font-size: 15px;
    cursor: pointer;
    transition: background 0.2s, color 0.2s;
}

.in-prev:hover,
.in-next:hover {
    background: #f3f4f6;
    color: #111;
}

/* The beats' words stack in one cell, so the box keeps its height, each centered in it; the old ones fade out before the new come in. */
.in-words {
    display: grid;
    text-align: center;
}

.in-beat {
    grid-area: 1 / 1;
    align-self: center;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.25s ease-in-out, visibility 0.25s;
}

.in-beat.on {
    opacity: 1;
    visibility: visible;
    transition-delay: 0.25s;
}

.in-title {
    margin: 0;
    color: #222;
    font-size: 22px;
    line-height: 30px;
    font-weight: 700;
}

/* Lines that wrap break into even halves, not a long line and a stray word. */
.in-lede {
    margin: 4px 0 0;
    color: #444;
    font-size: 18px;
    line-height: 26px;
    text-wrap: balance;
}

/* A beat with several lines (.in-ledes): they stack in one cell, and each comes in at its moment (intuition.js). */
.in-ledes {
    display: grid;
}

.in-ledes .in-lede {
    grid-area: 1 / 1;
    align-self: center; /* a shorter line sits mid-box, not at its top */
    opacity: 0;
    transition: opacity 0.25s ease-in-out;
}

.in-ledes .in-lede.on {
    opacity: 1;
    transition-delay: 0.2s;
}

.in-beat .fake {
    color: #dc2626;
}

/* The stage shows the splash's 1920x1080 frame cropped to the flow field (intuition.js scales and places each
   iframe); one iframe per cut, crossfading when the beats switch cuts. It can be dragged sideways with a mouse to
   scrub (not with a finger). */
.in-stage {
    position: relative;
    overflow: hidden;
    aspect-ratio: 1320 / 652;
    cursor: grab;
    background: #fff url(data/intuition_poster.webp) center / cover no-repeat; /* the first frame, until one is drawn */
}

.in-stage.drawn {
    background-image: none;
}

.in-stage iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 1920px;
    height: 1080px;
    border: 0;
    transform-origin: 0 0;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.5s ease-in-out;
}

.in-stage iframe.on {
    opacity: 1;
}

/* Under the stage: a seek bar over the whole story, in chapters: one per part, all the same width, split into its
   beats (intuition.js builds them); each beat's played stretch blue. Under it, each part's name under its chapter, the
   current one dark. On the right, play/pause (solid) and replay (the current part again). */
.in-scrub {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 12px;
    align-items: start;
    margin-top: 6px;
}

.in-buttons {
    display: flex;
    gap: 6px;
}

.in-play,
.in-replay {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 1px solid #2a6f97;
    border-radius: 50%;
    background: #2a6f97;
    color: #fff;
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}

.in-play:hover {
    background: #1f587a;
    border-color: #1f587a;
}

.in-play .ti-player-play {
    margin-left: 2px;
}

.in-replay {
    border-color: #d8d6cf;
    background: #fff;
    color: #2a6f97;
}

.in-replay:hover {
    border-color: #2a6f97;
    background: #eef4f8;
}

.in-track {
    position: relative;
    display: flex;
    gap: 8px;
    align-items: center;
    height: 32px;
    margin-top: -3px;
    cursor: pointer;
    touch-action: none;
}

.in-chap {
    display: flex;
    flex: 1 1 0;
    gap: 3px;
}

.in-seg {
    position: relative;
    height: 6px;
    overflow: hidden;
    border-radius: 3px;
    background: #e3e5e8;
    transition: height 0.15s;
}

.in-track:hover .in-seg,
.in-track.dragging .in-seg {
    height: 10px;
}

.in-seg i {
    position: absolute;
    inset: 0 auto 0 0;
    background: #2a6f97;
}

/* A tick where one of the beat's later lines comes in: a thin gap in the bar. */
.in-seg b {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 2px;
    margin-left: -1px;
    background: #fff;
}

.in-knob {
    position: absolute;
    top: 9px;
    z-index: 1;
    width: 14px;
    height: 14px;
    margin-left: -7px;
    border-radius: 50%;
    background: #2a6f97;
    box-shadow: 0 0 0 2px #fff;
    pointer-events: none;
    transition: transform 0.15s;
}

.in-track:hover .in-knob,
.in-track.dragging .in-knob {
    transform: scale(1.3);
}

/* Where a press on the bar would land: a hollow knob under the pointer, snapped to the ticks (intuition.js). */
.in-ghost {
    position: absolute;
    top: 9px;
    width: 14px;
    height: 14px;
    margin-left: -7px;
    box-sizing: border-box;
    border: 2px solid #2a6f97;
    border-radius: 50%;
    background: #fff;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s;
}

.in-ghost.on {
    opacity: 0.7;
}

.in-track:focus-visible {
    outline: 2px solid #2a6f97;
    outline-offset: 2px;
    border-radius: 4px;
}

.in-parts {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
}

.in-part {
    padding: 0;
    border: none;
    background: none;
    color: #9aa1a9;
    font: inherit;
    font-size: 14px;
    line-height: 20px;
    text-align: center;
    cursor: pointer;
    transition: color 0.3s;
}

.in-part:hover {
    color: #4b5563;
}

.in-part.on {
    color: #222;
    font-weight: 600;
}

.in-stage.dragging {
    cursor: grabbing;
}

/* QF3's actor update, always in view under the method text. */
.qf3-loss-box {
    padding: 12px 18px 14px;
    border: 1px solid #e6e6e6;
    border-radius: 12px;
    background: #f6f6f6;
}

/* Desktop: one line, the title in bold then "for a replay action…:". Phones: the title, then that line under it. */
.qf3-loss-title {
    margin: 0 0 8px;
    color: #374151;
    font-size: 14px;
    line-height: 21px;
    text-align: center;
}

.qf3-loss-title b {
    color: #222;
    font-weight: 600;
}

.qf3-given {
    display: none;
    margin: 0 0 8px;
    color: #374151;
    font-size: 14px;
    line-height: 21px;
    text-align: center;
    text-wrap: balance; /* no lone "τ:" on narrow phones */
}

/* Five lines, aligned at "=", each with a gray label on the right, in three groups split by faint hairlines
   (on the equations only): the setup and the velocity difference; the two terms built from it; the actor loss. */
.qf3-eqs {
    display: grid;
    grid-template-columns: auto auto auto;
    justify-content: center;
    align-items: baseline;
    row-gap: 6px;
    color: #222;
    font-size: 15px;
}

.qf3-eqs > .m:nth-child(3n + 1) {
    padding-right: 8px;
    text-align: right;
}

.qf3-eq-label {
    padding-left: 28px;
    color: #8a8f98;
    font-size: 13.5px;
    text-align: right;
    white-space: nowrap;
}

.qf3-eqs > .g {
    margin-top: 4px;
    padding-top: 5px;
}

.qf3-eqs > .m.g {
    border-top: 1px solid #ebebeb;
}

/* The phone-only rows (the first line, split in two). */
.qf3-eqs > .ph {
    display: none;
}

/* The step-by-step figure's dropdown: room around the figure, and its context text above it. */
.rw-compare > .rw-panel.cq-panel {
    padding: 4px 16px 14px;
}

.cq-intro {
    margin: 0 0 14px;
    color: #444;
    font-size: 15px;
    line-height: 22px;
}

/* The three dropdowns, stacked with even gaps. */
.dropdowns {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.dropdowns > .rw-prior {
    margin-top: 0;
}

/* "Why use the critic's gradient at all?": two panels on one critic landscape (scripts/build_grad_figure.py). */
.gv {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
    margin-top: 12px;
}

.gv figure {
    margin: 0;
}

.gv svg {
    display: block;
    width: 100%;
    height: auto;
}

.gv figcaption {
    margin-top: 6px;
    color: #555;
    font-size: 13.5px;
    line-height: 19px;
    text-align: center;
    text-wrap: balance;
}

.gv figcaption b {
    color: #222;
    font-weight: 600;
}

/* A dropdown that holds a short answer, not a figure. */
.rw-compare > .rw-panel.faq {
    padding: 4px 16px 14px;
}

.citation {
    margin: 0;
    padding: 20px;
    background-color: #eaeaea;
    border-radius: 10px;
    overflow-x: auto;
}

/* Last so it wins over the zero margins on text classes above. */
.add-top-padding {
    margin-top: 20px;
}

/* Breathing room between the page's main sections (context, results, citation, footer). */
main > .section + .section {
    margin-top: 80px;
}

/* Template credits: a quiet line tucked under the citation. */
footer.section {
    margin-top: 28px;
}

footer .paragraph {
    color: #999;
    font-size: 11px;
    line-height: 17px;
}

footer a:link,
footer a:visited {
    color: inherit;
}

@media screen and (max-width: 700px) {
    /* On a phone: no "Improving Flow Policies with RL" or "Results" headers, and the slideshow without its headlines
       or anything under the stage (just its lines and arrows). */
    .section-title.no-phone,
    .in-title,
    .in-scrub {
        display: none;
    }

    /* The intuition's lines, at the body text's size. */
    .in-lede {
        margin-top: 0;
        font-size: 16px;
        line-height: 24px;
    }
}

@media screen and (max-width: 900px) {
    .rw-body,
    .results-summary {
        grid-template-columns: 1fr;
    }

    .results-summary {
        gap: 16px;
    }
}

@media screen and (max-width: 550px) {
    /* The actor update on a phone: the title on its own line, no labels, and the math as large as the width allows. */
    .qf3-loss-box {
        padding: 12px 10px 14px;
    }

    .qf3-loss-title {
        margin-bottom: 2px;
        font-size: 16px;
    }

    .qf3-given-inline {
        display: none;
    }

    .qf3-given {
        display: block;
    }

    /* As big as the longest line (the bounded one-step prediction) fits: 16px from a 390px-wide phone up, smaller
       below. */
    .qf3-eqs {
        grid-template-columns: auto auto;
        font-size: min(16px, calc(4.8vw - 2.7px));
    }

    /* The first line split in two (the ph rows), one equation each. */
    .qf3-eqs > .dt {
        display: none;
    }

    .qf3-eqs > .m.ph {
        display: block;
    }

    .qf3-eqs > .m:nth-child(3n + 1) {
        padding-right: 5px;
    }

    .qf3-eq-label {
        display: none;
    }

    /* Two videos per view keep each carousel short; swipe to scroll. */
    .video-slider {
        gap: 8px;
    }

    /* The synced pair stays side by side: the comparison is the point. */
    .mr-pair {
        gap: 8px;
    }

    .video-slider.prompts figcaption {
        font-size: 11px;
        line-height: 15px;
    }

    /* No play/pause or speed buttons; each task plays at its own speed. */
    .mr-controls {
        display: none;
    }

    .mr-panel {
        padding: 10px 10px 6px;
    }

    .mr-tl {
        grid-template-columns: 76px 1fr;
    }

    .mr-hand {
        font-size: 11px;
    }

    .mr-chip {
        top: 5px;
        padding: 0 5px;
        font-size: 11px;
        line-height: 16px;
    }

    .mr-label {
        left: 5px;
    }

    .mr-rate {
        right: 5px;
    }

    .mr-len {
        margin-left: 2px;
    }

    .mr-dot {
        width: 14px;
        height: 14px;
        margin-left: -7px;
        border-radius: 7px;
        font-size: 9px;
        line-height: 14px;
    }

    /* Side by side, the base vs. QF3 clips are too small to read at phone width. */
    .race-pair {
        grid-template-columns: 1fr;
        gap: 8px;
    }

    .video-slider > * {
        flex-basis: calc((100% - 8px) / 2);
    }

    /* The plots are too small to read at phone width; the text carries their numbers. */
    .results-figure,
    .rw-plot,
    .rw-ours {
        display: none;
    }

    .video-placeholder {
        font-size: 12px;
        line-height: 16px;
    }

    .slider-btn {
        display: none;
    }

    body {
        padding: 12px 16px 32px;
    }

    main > .section + .section {
        margin-top: 56px;
    }

    footer.section {
        margin-top: 24px;
    }

    .authors {
        font-size: 12px;
        line-height: 19px;
    }

    .affiliations {
        font-size: 11.5px;
    }

    .author {
        margin: 0 0.45em;
    }

    .authors .text-star {
        top: -5px;
        font-size: 8px;
    }

    /* No TL;DR at phone width; the teaser keeps the gap it had below the links. */
    .tldr {
        display: none;
    }

    .filmstrip {
        height: 150px;
        margin-top: 32px;
    }

    /* The subtitle halves are too wide for one line each; let it wrap evenly instead. */
    .subheader {
        font-size: 22px;
        line-height: 32px;
        text-wrap: balance;
    }

    .subheader span {
        display: inline;
    }

    .citation {
        padding: 16px;
    }

    .rw {
        padding: 12px;
    }

    /* The slideshow's box reaches most of the way into the body's 16px gutter, and its stage runs to the box's sides, so
       it's about as wide, and so as tall, as a phone allows; the animation is about 2:1 throughout, so a tighter crop
       wouldn't make it taller. */
    .rw.intuition {
        margin-left: -10px;
        margin-right: -10px;
        padding: 12px;
    }

    .in-stage {
        margin: 0 -12px;
    }

    .rw-body {
        grid-template-columns: 1fr;
    }
}
