/**
 * Perspective v2 — the visually led index and the article pages.
 *
 * Layers on perspectives.css: the tokens, .kcp-wrap, .kcp-html newsletter
 * normalisation, share row and closing band are all shared. Everything here is
 * about giving the imagery room.
 */

/* ---------- Width ---------- */

/*
 * v2 runs much wider than v1: the reference gives the imagery most of the
 * viewport with only a slim margin, and a 1100px column makes the covers look
 * like thumbnails.
 */
.kcv .kcp-wrap {
    max-width: 1680px;
    padding-inline: 9rem;
}

/*
 * The article's reading column stays narrow even though the page runs wide.
 * 860px is the width the newsletter exports are built to.
 *
 * This is deliberately a FIXED 860px and must not be var(--kcv-read-width):
 * that variable is measured *from the paragraphs inside this element*, so
 * feeding it back in here makes a loop — every re-measure took the export's own
 * cell inset off again and the column walked itself down (860 -> 840 -> 800 …)
 * on each load and resize, dragging the aligned chrome out of step with the
 * text it was supposed to line up with. Only chrome may consume the measurement.
 */
.kcv-single .kcp-html {
    max-width: 860px;
}

/*
 * The title sits on the article's width, not the page's. Left on the plain
 * .kcp-wrap it inherited the 9rem page gutter, so the heading box came out at
 * 572px against 840px of body copy and the title wrapped far too early.
 */
.kcv-article__head .kcp-wrap {
    --kcv-head-pad: 24px;
    max-width: calc(var(--kcv-read-width, 860px) + 2 * var(--kcv-head-pad));
    padding-inline: var(--kcv-head-pad);
}

/* ---------- Index hero ---------- */

/*
 * Tight on purpose. The hero used to fill the fold on its own, so the index
 * opened on a title card with no sign there was anything below it; the padding
 * here and on .kcv-list is set so the first cover breaks the fold on load.
 *
 * --kcv-hero-clear is measured in JS: on a theme with a fixed header (Jupiter
 * on the live site) the page starts at the very top of the viewport and runs
 * underneath it, which cropped the top of the title. It resolves to 0 where the
 * header sits in the flow, so this stays 56px locally.
 */
.kcv-hero {
    position: relative;
    overflow: hidden;
    padding-block: calc(56px + var(--kcv-hero-clear, 0px)) 40px;
    text-align: center;
    /* Flat black — the tonal panel and the coral radial wash that used to sit
       behind the title were dropped at the client's request. */
    background: var(--kcp-bg);
}

.kcv-hero .kcp-wrap {
    position: relative;
    z-index: 1;
}

.kcv-hero__inner {
    max-width: 780px;
    margin: 0 auto;
    display: grid;
    gap: 18px;
    justify-items: center;
}

.kcv-hero .kcp-lede {
    padding-top: 18px;
}

.kcv-hero__note {
    max-width: 480px;
}

/* ---------- The index itself ---------- */

.kcv-list {
    padding-block: 96px 0;
}

/*
 * Immersive bands, the same shape as the Speaking & Workshops page: a
 * full-bleed cover on one side gradienting to black, ranged copy on the other,
 * alternating down the page. The bands butt up against each other, so the
 * rhythm comes from each band's own padding rather than a gap between them.
 */
.kcv-entry {
    position: relative;
    overflow: hidden;
    padding-block: 120px;
    /*
     * A floor, so the band isn't sized by how long the copy happens to be.
     * Without it these ran 373-424px against the speakers' 614-670px, because
     * a perspective's copy is far shorter than a speaker's — and at `cover` a
     * short band is exactly what crops the image. 40rem puts the band at the
     * same ~2.4:1 as the speakers page, which takes a 16:9 featured image from
     * 44% of its height visible to about 75%.
     */
    min-height: 40rem;
    display: flex;
    align-items: center;
}

.kcv-entry > .kcp-wrap {
    width: 100%;
}

/*
 * The cover is the band's background and its link. It sits under the scrim
 * (which is pointer-events: none) and under the copy, so clicking the artwork
 * opens the issue while the copy keeps its own links.
 */
/*
 * The image box is given the IMAGE's aspect ratio, so nothing is cropped.
 *
 * The speakers page stretches its portrait edge to edge at `cover` and simply
 * loses whatever doesn't fit — fine for a face, where the crop only takes body.
 * Here the covers are stills that were framed deliberately, and a full-bleed
 * band is ~2.4:1, so `cover` was throwing away 25% of a 16:9 image and 54% of a
 * near-square one. No band height fixes that: it's the ratio mismatch, not the
 * size.
 *
 * So the box spans the band's height and takes its width from the cover's own
 * ratio (`--kcv-cover-ratio`, measured per band in perspective-v2.js). At that
 * ratio `cover` has nothing left to crop. It's anchored to the outer edge and
 * runs under the copy, where the scrim and the mask below dissolve it — so it
 * still reads as a full-bleed band, it just isn't cut down to fit one.
 */
.kcv-entry__bg {
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    left: auto;
    z-index: 0;
    display: block;
    width: auto;
    aspect-ratio: var(--kcv-cover-ratio, 16 / 9);
    max-width: 100%;
    background-size: cover;
    background-position: center;
    opacity: 0.55;
    transition: transform 1s ease, opacity 1s ease;
    /* Dissolves the inner edge whatever width the ratio gives the box — the
       scrim alone only hides it when the box happens to reach far enough in. */
    -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 26%);
    mask-image: linear-gradient(to right, transparent 0%, #000 26%);
}

.kcv-entry:hover .kcv-entry__bg {
    transform: scale(1.04);
    opacity: 0.7;
}

/* Flipped bands anchor the cover left and mirror the mask — by position, never
   `scaleX(-1)`: mirroring reverses any type in the artwork. */
.kcv-entry--flip .kcv-entry__bg {
    right: auto;
    left: 0;
    -webkit-mask-image: linear-gradient(to left, transparent 0%, #000 26%);
    mask-image: linear-gradient(to left, transparent 0%, #000 26%);
}

/* No cover resolved — keep the band alive rather than dropping to flat black. */
.kcv-entry__bg--empty {
    inset: 0;
    width: auto;
    max-width: none;
    aspect-ratio: auto;
    -webkit-mask-image: none;
    mask-image: none;
    transform: none;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding-inline: 8%;
    opacity: 1;
    background:
        radial-gradient(60% 100% at 78% 40%, rgba(232, 115, 90, 0.18), transparent 66%),
        var(--kcp-panel-alt);
    color: var(--kcp-accent);
    font-size: clamp(40px, 6vw, 72px);
    font-weight: 300;
}

.kcv-entry--flip .kcv-entry__bg--empty {
    justify-content: flex-start;
    background:
        radial-gradient(60% 100% at 22% 40%, rgba(232, 115, 90, 0.18), transparent 66%),
        var(--kcp-panel-alt);
}

/* Pulls the black across whichever side the copy occupies. */
.kcv-entry__scrim {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    /*
     * Pulls the black across whichever side the copy occupies — side only.
     *
     * The speakers page stacks a second `to top` layer under this one to ground
     * a portrait band. Dropped here at the client's request: with the cover
     * sized to its own ratio there's nothing to ground, and that layer was
     * dimming the bottom 45% of artwork the whole point was to show whole —
     * on "Sunday Show Time" precisely where the headline sits.
     */
    background:
        linear-gradient(to right, var(--kcp-bg) 20%, rgba(0, 0, 0, 0.65) 52%, rgba(0, 0, 0, 0.15) 100%);
}

.kcv-entry--flip .kcv-entry__scrim {
    background:
        linear-gradient(to left, var(--kcp-bg) 20%, rgba(0, 0, 0, 0.65) 52%, rgba(0, 0, 0, 0.15) 100%);
}

.kcv-entry__inner {
    position: relative;
    z-index: 2;
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: 40px;
}

/* Ranged left, not centred — matching the speakers bands. */
.kcv-entry__copy {
    grid-column: 1 / span 6;
    display: grid;
    gap: 18px;
    justify-items: start;
    text-align: left;
    align-content: center;
}

.kcv-entry--flip .kcv-entry__copy {
    grid-column: 7 / span 6;
}

.kcv-entry__meta {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--kcp-accent);
    margin: 0;
}

.kcv-entry__dot {
    opacity: 0.6;
    margin-inline: 4px;
}

/* The title carries the band, so it runs larger than it did in the grid. */
.kcv-entry__title {
    font-size: 42px;
    font-weight: 300;
    line-height: 1.15;
    margin: 0;
}

.kcv-entry__title a {
    color: var(--kcp-text);
    text-decoration: none;
    transition: color 0.2s ease;
}

.kcv-entry:hover .kcv-entry__title a {
    color: var(--kcp-title);
}

.kcv-entry__teaser {
    font-size: 16px;
    font-weight: 300;
    line-height: 1.6;
    color: var(--kcp-text-muted);
    max-width: 34em;
    margin: 0;
}

.kcv-read {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--kcp-accent);
    text-decoration: none;
    padding-top: 4px;
    transition: color 0.2s ease;
}

.kcv-read:hover,
.kcv-entry:hover .kcv-read {
    color: var(--kcp-title);
}

/* ---------- Article page ---------- */

.kcv-article__head {
    padding-block: 100px 48px;
    text-align: center;
}

.kcv-backlink {
    color: var(--kcp-accent);
    text-decoration: none;
    border-bottom: 1px solid transparent;
    transition: border-color 0.2s ease;
}

.kcv-backlink:hover {
    border-bottom-color: var(--kcp-accent);
}

.kcv-article__title {
    font-size: clamp(34px, 4.4vw, 56px);
    font-weight: 300;
    line-height: 1.12;
    color: var(--kcp-text);
    margin: 18px 0 0;
}

.kcv-article__standfirst {
    font-size: 19px;
    font-weight: 300;
    line-height: 1.6;
    color: var(--kcp-text-muted);
    margin: 20px auto 0;
    max-width: 62ch;
}

/* Full-bleed, because the imagery is the reason for this design. */
.kcv-article__cover {
    margin: 0 0 56px;
}

.kcv-article__cover img {
    width: 100%;
    height: auto;
    max-height: 76vh;
    object-fit: cover;
}

.kcv-single .kcp-share {
    max-width: var(--kcv-read-width, 860px);
    margin-inline: auto;
    justify-content: center;
    /*
     * Even above and below. The base rule sets padding-top: 24px, so the row
     * sat 24px under its own rule and 56px above the next one — the buttons
     * read as belonging to the article above rather than sitting between the
     * two rules.
     */
    padding-block: 48px;
}

/* ---------- Read next ---------- */

.kcv-next {
    padding-block: 0 90px;
}

/*
 * On the article's own 860px column, and its rule lines up with the share rule
 * directly above it rather than running the full page width.
 */
.kcv-next__inner {
    max-width: var(--kcv-read-width, 860px);
    margin-inline: auto;
    padding-top: 72px;
    border-top: 1px solid var(--kcp-border);
}

.kcv-next__label {
    color: var(--kcp-text-muted);
    text-align: center;
    margin-bottom: 32px;
}

/*
 * Stacked and centred, NOT the index's cover-left / copy-right row. At the foot
 * of an article that row read as another index entry rather than as a pointer
 * to one more thing, and the copy sat a long way right of the cover it belongs
 * to — a single centred column leaves nothing to misread.
 */
.kcv-next__card {
    display: grid;
    gap: 28px;
    justify-items: center;
    text-decoration: none;
}

.kcv-next__media {
    display: block;
    width: 100%;
    max-width: 380px;
    background: var(--kcp-panel);
    transform-origin: center;
    transition: transform 0.7s cubic-bezier(0.4, 0, 0.2, 1);
}

.kcv-next__media img {
    width: 100%;
    height: auto;
}

.kcv-next__card:hover .kcv-next__media {
    transform: scale(1.035);
}

.kcv-next__copy {
    display: grid;
    gap: 14px;
    justify-items: center;
    text-align: center;
}

.kcv-next__title {
    font-size: 30px;
    font-weight: 300;
    line-height: 1.2;
    color: var(--kcp-text);
    transition: color 0.2s ease;
}

.kcv-next__card:hover .kcv-next__title {
    color: var(--kcp-title);
}

/* ---------- Reveal on scroll ---------- */

/*
 * Entries fade up as they come into view. The hidden state is scoped to
 * `.kcv-js`, a class the script puts on <html> — without JS (or with the file
 * failing to load) nothing is ever un-hidden, so the index would be a blank
 * page. Anyone who has asked for reduced motion gets the page as-is.
 */
.kcv-js .kcv-reveal {
    opacity: 0;
    transform: translateY(28px);
}

.kcv-js .kcv-reveal.is-in {
    opacity: 1;
    transform: none;
    transition:
        opacity 1.8s cubic-bezier(0.22, 0.61, 0.36, 1),
        transform 1.8s cubic-bezier(0.22, 0.61, 0.36, 1);
}

@media (prefers-reduced-motion: reduce) {
    .kcv-js .kcv-reveal {
        opacity: 1;
        transform: none;
    }
}

/* ---------- Article: sticky back bar ---------- */

/*
 * A thin black rail carrying the way out and the title of what you're in.
 * Sticky rather than fixed so it scrolls with the page inside .kcv-single and
 * doesn't sit over the footer or a theme's own chrome once you leave the
 * article.
 */
/*
 * --kcv-chrome is the measured bottom of the site's own fixed furniture (admin
 * bar + a fixed theme header). Pinning to 0 put this bar underneath Jupiter's
 * header, which is fixed at z-index 200 — the bar was rendering, just never
 * visible. The fallbacks below are the admin-bar-only case for when JS hasn't
 * run yet.
 */
.kcv-topbar {
    position: sticky;
    top: var(--kcv-chrome, 0px);
    z-index: 30;
    /* Solid, not translucent: the newsletter markup scrolling underneath is
       high-contrast and ghosted straight through a blurred bar. */
    background: var(--kcp-bg);
    border-bottom: 1px solid var(--kcp-border);
}

/*
 * Jupiter's header is rgba(0, 0, 0, 0.85), so the article scrolls visibly
 * through it and the 67px of translucent nav above this bar reads as a gap
 * between the two. Carry the bar's black up behind the nav — the nav is
 * z-index 200 against this bar's 30, so it still paints on top, it just gets an
 * opaque backing instead of moving artwork. Height 0 on a theme with no fixed
 * chrome, so nothing is painted where nothing is needed.
 */
.kcv-topbar::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 100%;
    height: var(--kcv-chrome, 0px);
    background: var(--kcp-bg);
    pointer-events: none;
}

/* The admin bar is fixed over the top of everything on the front end. */
.admin-bar .kcv-topbar {
    top: var(--kcv-chrome, 32px);
}

/*
 * The rail itself is full-bleed; what sits on it lines up with the article.
 * Not the page's 9rem gutter — that would range the back link a long way left
 * of the text it belongs to. 860px is the reading column, so this is the same
 * box as .kcp-html.
 */
.kcv-topbar .kcp-wrap {
    --kcv-topbar-pad: 24px;
    max-width: calc(var(--kcv-read-width, 860px) + 2 * var(--kcv-topbar-pad));
    padding-inline: var(--kcv-topbar-pad);
}

.kcv-topbar__inner {
    display: flex;
    align-items: center;
    gap: 20px;
    min-height: 52px;
    padding-block: 8px;
}

.kcv-topbar__back {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex: none;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--kcp-accent);
    text-decoration: none;
    transition: color 0.2s ease;
}

.kcv-topbar__back:hover,
.kcv-topbar__back:focus-visible {
    color: var(--kcp-title);
}

.kcv-topbar__back svg {
    transition: transform 0.2s ease;
}

.kcv-topbar__back:hover svg {
    transform: translateX(-3px);
}

.kcv-topbar__rule {
    flex: none;
    width: 1px;
    height: 16px;
    background: var(--kcp-border-strong);
}

/* One line, however long the title is. */
.kcv-topbar__title {
    min-width: 0;
    font-size: 14px;
    font-weight: 300;
    line-height: 1.3;
    color: var(--kcp-text-soft);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ---------- Narrow screens ---------- */

@media (max-width: 1400px) {
    .kcv .kcp-wrap {
        padding-inline: 4rem;
    }
}

@media (max-width: 1100px) {
    .kcv .kcp-wrap {
        padding-inline: 28px;
    }
}

@media (max-width: 900px) {
    .kcv .kcp-wrap {
        padding-inline: 20px;
    }

    .kcv-hero {
        padding-block: 48px 36px;
    }

    .kcv-list {
        padding-block: 64px;
    }

    /*
     * Stacked, not overlaid.
     *
     * The band works on desktop because the cover sits beside the copy and the
     * side scrim keeps the two apart. Once the copy spans the full width there
     * is no "beside" left: the cover ends up directly behind the text, and no
     * amount of scrim strength makes that reliably readable — it was 0.45 black
     * at the top of the band over a 0.45-opacity image, so the artwork read
     * straight through the copy. At this width the cover becomes its own block
     * above the copy, at full strength, and the copy sits on plain black.
     */
    .kcv-entry {
        display: block;
        min-height: 0;
        padding-block: 0 56px;
    }

    .kcv-entry__bg,
    .kcv-entry--flip .kcv-entry__bg {
        position: relative;
        inset: auto;
        width: 100%;
        max-width: none;
        aspect-ratio: var(--kcv-cover-ratio, 16 / 9);
        margin-bottom: 28px;
        opacity: 1;
        transform: none;
        -webkit-mask-image: none;
        mask-image: none;
    }

    /* No cover to size the box, so give it something to occupy. */
    .kcv-entry__bg--empty {
        aspect-ratio: 16 / 9;
    }

    .kcv-entry:hover .kcv-entry__bg {
        transform: none;
    }

    /* Nothing to scrim once the copy is off the artwork. */
    .kcv-entry__scrim {
        display: none;
    }

    .kcv-entry__copy,
    .kcv-entry--flip .kcv-entry__copy {
        grid-column: 1 / -1;
    }

    .kcv-entry__title {
        font-size: 30px;
    }

    .kcv-article__head {
        padding-block: 56px 32px;
    }

    .kcv-article__cover {
        margin-bottom: 32px;
    }

    .kcv-next {
        padding-block: 0 56px;
    }

    .kcv-next__inner {
        padding-top: 48px;
    }

    .kcv-next__title {
        font-size: 26px;
    }

    /* The admin bar goes taller and stops being fixed below 782px. */
    .admin-bar .kcv-topbar {
        top: var(--kcv-chrome, 46px);
    }

    .kcv-topbar .kcp-wrap {
        --kcv-topbar-pad: 20px;
    }

    .kcv-topbar__inner {
        gap: 14px;
        min-height: 48px;
    }

    .kcv-topbar__title {
        font-size: 13px;
    }
}

@media (max-width: 782px) {
    .admin-bar .kcv-topbar {
        top: var(--kcv-chrome, 0px);
    }
}

/* A hover scale is meaningless on touch, and the transition just delays the tap. */
@media (hover: none) {
    .kcv-entry__bg {
        transition: none;
    }
}
