/**
 * Just Orthodontics — sections.
 *
 * §01  Hero
 * §02  Split panels
 * §03  Statistics
 * §04  Accreditations
 * §05  Lead clinician panel
 * §06  Video panel
 * §07  Finance
 * §08  CTA strip
 * §09  Photographic CTA
 * §10  Contact
 */

/* ═══ §01 Hero ════════════════════════════════════════════════ */

.jo-hero {
    position: relative;
    display: flex;
    align-items: flex-end;
    min-height: var(--jo-hero-height-sub);
    padding-top: calc(var(--jo-admin-bar) + var(--jo-header-height) + clamp(40px, 5vw, 90px));
    padding-bottom: clamp(48px, 5vw, 88px);
    isolation: isolate;
    color: var(--jo-cream);
    overflow: hidden;
}

/* The homepage hero is the tall one — Figma 915 of a 1728 frame. */
.jo-hero--tall { min-height: var(--jo-hero-height); }

.jo-hero__media {
    position: absolute;
    inset: 0;
    z-index: -2;
    background: var(--jo-navy);
}

.jo-hero__img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/**
 * The hero treatment, in layers.
 *
 * A short wash from the top keeps the header legible against whatever the
 * photograph happens to be doing up there. Under it sits the veil — the navy
 * tone the design puts over every hero photograph — whose strength is a
 * variant, because the frame does not use one value everywhere. A left-aligned
 * hero adds a third layer, the sideways wash behind its copy column; a centred
 * one does not, which is exactly why it needs a deeper veil to hold a heading
 * over the middle of a picture.
 *
 * The photograph is never touched. Nothing here is baked into an asset, so the
 * same clean image can be used at any strength, and changing the strength is a
 * variant class rather than a new export.
 */
.jo-hero__scrim {
    position: absolute;
    inset: 0;
    /*
     * Above the photograph, not behind it.
     *
     * The scrim is a child of the media wrapper, and that wrapper is already
     * the hero's background layer. A negative index here does not put the
     * scrim behind the hero — it puts it behind its own sibling <img>, which
     * is why the veil was drawn but never seen.
     */
    z-index: 1;
    background: var(--jo-hero-scrim-top), var(--jo-hero-veil);
}

/* The three steps. `standard` is the fallback for a hero that names none. */
.jo-hero                    { --jo-hero-veil: var(--jo-hero-veil-standard); }
.jo-hero--veil-light        { --jo-hero-veil: var(--jo-hero-veil-light); }
.jo-hero--veil-standard     { --jo-hero-veil: var(--jo-hero-veil-standard); }
.jo-hero--veil-strong       { --jo-hero-veil: var(--jo-hero-veil-strong); }

/* Left-aligned heroes carry the directional wash as well. */
.jo-hero--left .jo-hero__scrim,
.jo-hero--with-leads .jo-hero__scrim {
    background: var(--jo-hero-scrim-top), var(--jo-hero-scrim-copy), var(--jo-hero-veil);
}

.jo-hero__inner {
    position: relative;
    width: 100%;
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: clamp(24px, 3vw, 56px);
}

.jo-hero__copy { max-width: 640px; }

.jo-hero--centre .jo-hero__inner { justify-content: center; }

.jo-hero--centre .jo-hero__copy {
    text-align: center;
    max-width: 760px;
    margin-inline: auto;
}

.jo-hero__eyebrow { margin-bottom: var(--jo-space-4); }

/**
 * The hero display, at its two sizes.
 *
 * The full 100px H1 belongs to the homepage alone — it is a composition, set
 * against a tall photograph with room to be that big. Every inner page draws
 * its hero heading at a little over 60, and rendering them all at the homepage
 * size was the single largest typographic difference from the frame.
 */
.jo-hero .jo-hero__title {
    color: var(--jo-cream);
    margin-bottom: var(--jo-space-5);
    font-size: var(--jo-hero-title-sub);
    line-height: 1.05;
}

.jo-hero--tall .jo-hero__title {
    font-size: var(--jo-h1);
    line-height: var(--jo-lh-h1);
}

.jo-hero__text {
    color: rgba(var(--jo-cream-rgb), .92);
    max-width: 58ch;
    font-size: var(--jo-body-lg);
}

.jo-hero--centre .jo-hero__text { margin-inline: auto; }
.jo-hero--centre .jo-hero__actions { justify-content: center; }

/* The homepage hero's copy is left-aligned even in the centred layout, because
   it sits beside the clinician card rather than under a centred heading. */
.jo-hero--with-leads .jo-hero__inner { justify-content: space-between; }
.jo-hero--with-leads .jo-hero__copy { text-align: left; margin-inline: 0; }
.jo-hero--with-leads .jo-hero__text { margin-inline: 0; }
.jo-hero--with-leads .jo-hero__actions { justify-content: flex-start; }

/* ── The lead-clinician card ──────────────────────────────── */

.jo-hero__leads { flex: 0 0 auto; width: clamp(240px, 20vw, 292px); }

/**
 * The clinician card in the hero.
 *
 * The shared glass is a pale wash, which works where it sits over the darker
 * part of a photograph and fails where it does not — on a phone the hero crops
 * to a brighter area and the cream text on it measured 1.3:1, which is not
 * legible by any standard.
 *
 * So this one card carries a navy tint rather than the neutral wash. It is still
 * glass and still blurs what is behind it; it simply guarantees a dark ground
 * for the cream text regardless of where the photograph happens to be light,
 * instead of depending on the crop.
 *
 * It is also the one place on the site where an inner surface genuinely sits
 * inside the outer corner's arc, so the two corners are held concentric:
 *
 *     outer = inner (8) + padding (14) + border (1) = 23px
 *
 * Derived rather than typed, so the card's corner keeps following its
 * photograph's corner if the padding is ever changed. It is written against the
 * border box because that is the edge `border-radius` actually curves.
 */
.jo-leads-card {
    --jo-leads-card-border: 1px;
    --jo-leads-card-inset: 14px;
    --jo-leads-card-inner-radius: var(--jo-radius-sm);

    padding: var(--jo-leads-card-inset);
    border: var(--jo-leads-card-border) solid var(--jo-glass-border);
    border-radius: calc(var(--jo-leads-card-inner-radius)
                      + var(--jo-leads-card-inset)
                      + var(--jo-leads-card-border));
    background: linear-gradient(
        180deg,
        rgba(var(--jo-navy-rgb), .52) 0%,
        rgba(var(--jo-navy-rgb), .68) 100%);
    -webkit-backdrop-filter: var(--jo-glass-blur);
    backdrop-filter: var(--jo-glass-blur);
}

.jo-leads-card__media {
    border-radius: var(--jo-leads-card-inner-radius);
    overflow: hidden;
    margin-bottom: var(--jo-space-4);
}

.jo-leads-card__eyebrow {
    font-size: var(--jo-eyebrow-size);
    letter-spacing: var(--jo-eyebrow-tracking);
    color: rgba(var(--jo-cream-rgb), .8);
    margin-bottom: 6px;
}

.jo-leads-card__names {
    font-family: var(--jo-font-display);
    font-size: clamp(21px, 1.7vw, 29px);
    line-height: 1.05;
    color: var(--jo-cream);
    margin-bottom: var(--jo-space-4);
}

.jo-leads-card__names strong { font-weight: 700; }

.jo-leads-card__cta { width: 100%; }

/* ═══ §02 Split panels ════════════════════════════════════════ */

/**
 * Copy beside an arched photograph.
 *
 * `media-left` / `media-right` set the order explicitly rather than relying on
 * source order, so an editor can flip a panel without the markup changing and
 * without the reading order on a phone ever becoming copy-then-image-then-copy.
 */
/**
 * The image-and-copy panels.
 *
 * Narrower than the page container: the design sets this block at 1271 of the
 * 1728 frame, which is what keeps the paragraph to a readable measure instead of
 * letting it run the full width of the page.
 *
 * The two tracks are the design's own 560 and 631, written as a ratio so they
 * hold at every width rather than only at the one they were measured on.
 */
.jo-split {
    display: grid;
    grid-template-columns: minmax(0, 560fr) minmax(0, 631fr);
    align-items: center;
    gap: clamp(28px, 4.6vw, 80px);
    max-width: var(--jo-container-split);
    margin-inline: auto;
}

.jo-split__media { position: relative; }

.jo-split--media-right { grid-template-columns: minmax(0, 631fr) minmax(0, 560fr); }
.jo-split--media-right .jo-split__media { order: 2; }
.jo-split--media-right .jo-split__copy  { order: 1; }

.jo-split__copy .jo-eyebrow-pill { margin-bottom: var(--jo-space-4); }
.jo-split__copy .jo-h2 { margin-bottom: var(--jo-space-4); }
.jo-split__copy .jo-prose { margin-top: var(--jo-space-5); }

/* ═══ §03 Statistics ══════════════════════════════════════════ */

.jo-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: clamp(20px, 2.4vw, 40px);
    text-align: center;
}

.jo-stats__item { display: grid; gap: 6px; }

.jo-stats__value {
    font-family: var(--jo-font-display);
    font-size: var(--jo-stat-value);
    line-height: 1.1;
    color: var(--jo-cream);
    letter-spacing: .04em;
}

.jo-stats__value--stars {
    display: flex;
    justify-content: center;
    gap: 4px;
    color: var(--jo-cream);
}

.jo-stats__star { width: var(--jo-stat-star); height: var(--jo-stat-star); }

.jo-stats__label {
    font-size: var(--jo-label-size);
    letter-spacing: var(--jo-label-tracking);
    text-transform: uppercase;
    color: var(--jo-on-navy);
}

/**
 * ── The band at narrower widths ──────────────────────────────────
 *
 * `auto-fit` was choosing its own arrangement as the viewport narrowed, and the
 * choices were poor: three across with the fifth-star item alone underneath at
 * 600, two ragged columns of unequal height at 430. Below 768 the count is set
 * rather than inferred.
 */
@media (max-width: 767px) {
    .jo-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/**
 * Stacked, one statistic to a row.
 *
 * At this width two columns leaves each figure about 160px to live in, which is
 * narrower than its own label — so the figures go one to a row, step up to
 * carry the row on their own, and take a hairline between them. The rule is the
 * one the site already uses to separate rows on navy, so the band gains a
 * structure rather than a new decoration.
 */
@media (max-width: 600px) {
    .jo-stats {
        grid-template-columns: minmax(0, 1fr);
        gap: 0;
    }

    .jo-stats__item {
        gap: 10px;
        padding-block: clamp(22px, 5.4vw, 30px);
        border-top: 1px solid var(--jo-line-on-navy);
    }

    .jo-stats__item:first-child { border-top: 0; padding-top: 0; }
    .jo-stats__item:last-child  { padding-bottom: 0; }

    .jo-stats__value { font-size: var(--jo-stat-value-stacked); }

    /* The stars are the value on their row, so they scale with the figures. */
    .jo-stats__star { width: var(--jo-stat-star-stacked); height: var(--jo-stat-star-stacked); }
    .jo-stats__value--stars { gap: 7px; }
}

/* ═══ §04 Accreditations ══════════════════════════════════════ */

.jo-accred__eyebrow {
    text-align: center;
    font-size: var(--jo-label-size);
    letter-spacing: var(--jo-label-tracking);
    text-transform: uppercase;
    color: var(--jo-soft);
    margin-bottom: var(--jo-space-5);
}

.jo-accred {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: clamp(10px, 1.1vw, 16px);
}

.jo-accred__item > span,
.jo-accred__item > a {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 82px;
    padding: var(--jo-space-4);
    border: 1px solid var(--jo-border);
    border-radius: var(--jo-radius-sm);
    background: var(--jo-white);
    text-align: center;
    transition: border-color var(--jo-dur) var(--jo-ease);
}

.jo-accred__item > a:hover { border-color: var(--jo-pill); }

.jo-accred__logo {
    max-height: 40px;
    width: auto;
    object-fit: contain;
}

.jo-accred__name { font-size: var(--jo-body-sm); font-weight: 500; color: var(--jo-heading); }
.jo-accred__text { font-size: var(--jo-body-sm); color: var(--jo-soft); }

/*
 * A placeholder badge now carries the organisation's name as text rather than
 * stand-in artwork, so it is not dimmed — it is real, readable copy. The flag
 * beneath it is shown to signed-in editors only.
 */

.jo-accred__flag {
    display: block;
    margin-top: 6px;
    font-size: var(--jo-label-size);
    letter-spacing: .04em;
    color: var(--jo-soft);
    text-align: center;
}

/* ═══ §05 Lead clinician panel ════════════════════════════════ */

.jo-lead {
    display: grid;
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1fr);
    align-items: center;
    gap: clamp(28px, 4.6vw, 80px);
}

.jo-arch--lead { display: grid; }

.jo-lead__frame {
    grid-area: 1 / 1;
    margin: 0;
    height: 100%;
    opacity: 0;
    transition: opacity var(--jo-flip-dur) var(--jo-ease);
}

.jo-lead__frame.is-active { opacity: 1; }
.jo-lead__frame:not(.is-active) { pointer-events: none; }

.jo-lead__copy .jo-eyebrow-pill { margin-bottom: var(--jo-space-5); }

.jo-lead__person { display: grid; gap: var(--jo-space-3); }
.jo-lead__person[hidden] { display: none; }

.jo-lead__name { color: var(--jo-heading); }

.jo-lead__meta { font-size: var(--jo-body-sm); color: var(--jo-body); }

.jo-lead__gdc {
    font-size: var(--jo-body-sm);
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--jo-soft);
}

.jo-lead__intro { color: var(--jo-body); max-width: 56ch; }
.jo-lead__cta { margin-top: var(--jo-space-3); justify-self: start; }

.jo-lead__controls {
    display: flex;
    align-items: center;
    gap: var(--jo-space-4);
    margin-top: var(--jo-space-6);
}

.jo-lead__dots { display: flex; gap: 7px; }

.jo-lead__dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--jo-border);
    transition: background-color var(--jo-dur-fast) var(--jo-ease),
                transform var(--jo-dur-fast) var(--jo-ease);
}

.jo-lead__dot.is-active { background: var(--jo-navy); transform: scale(1.25); }

.jo-team-intro {
    max-width: 78ch;
    margin-inline: auto;
    text-align: center;
    font-size: var(--jo-body-lg);
    color: var(--jo-body);
}

/* ═══ §06 Video panel ═════════════════════════════════════════ */

.jo-video-panel {
    display: grid;
    grid-template-columns: minmax(0, 0.72fr) minmax(0, 1fr);
    align-items: center;
    gap: clamp(24px, 3vw, 56px);
}

.jo-video-panel__eyebrow {
    font-size: var(--jo-label-size);
    letter-spacing: var(--jo-label-tracking);
    color: var(--jo-soft);
    margin-bottom: 8px;
}

.jo-video-panel__title {
    font-family: var(--jo-font-display);
    color: var(--jo-heading);
    margin-bottom: var(--jo-space-3);
}

.jo-video-panel__text { font-size: var(--jo-card-body); line-height: 1.6; color: var(--jo-body); }

.jo-video {
    --jo-play-size: 64px;
    --jo-play-size-docked: 48px;
    --jo-play-dock-inset: 14px;
}

.jo-video__stage {
    position: relative;
    display: grid;
    place-items: center;
    aspect-ratio: 16 / 9;
    border-radius: var(--jo-radius-md);
    overflow: hidden;
    background: var(--jo-navy);
}

/**
 * The cover.
 *
 * Held back to just over half opacity so the white play control reads against
 * whatever photograph is chosen — the panel's navy does the rest of the work.
 * With no video attached there is no control to protect, so the photograph is
 * shown as it was taken.
 */
.jo-video__poster {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: var(--jo-focus, 50% 50%);
    opacity: .55;
    transition: opacity var(--jo-dur-slow) var(--jo-ease);
}

.jo-video[data-video-static] .jo-video__poster { opacity: 1; }

.jo-video__stage iframe,
.jo-video__stage video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

/**
 * The control layer.
 *
 * Sits over the whole stage, above the player, and is the thing that is
 * hovered — the player is a cross-origin iframe and does not hand :hover up to
 * its ancestors, so anything waiting on the stage itself would never hear about
 * a pointer once the video was running. Owning the pointer here is also what
 * lets a click anywhere on the picture pause it, the way a video should.
 */
.jo-video__controls {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: grid;
    place-items: center;
}

/**
 * The play control.
 *
 * A white ring, with the radar pulse drawn on two absolutely-positioned rings
 * rather than on the button itself — so the pulse can scale past the button's
 * bounds without changing its hit area or nudging anything around it. The
 * animation lives in motion.css and stops entirely under reduced-motion.
 */
.jo-play {
    position: relative;
    z-index: 2;
    display: grid;
    place-items: center;
    width: var(--jo-play-size);
    height: var(--jo-play-size);
    border-radius: 50%;
    border: 1.5px solid var(--jo-white);
    color: var(--jo-white);
    background: rgba(var(--jo-navy-rgb), .28);
    -webkit-backdrop-filter: blur(3px);
    backdrop-filter: blur(3px);
    transition: background-color var(--jo-dur) var(--jo-ease),
                transform var(--jo-dur) var(--jo-ease);
}

.jo-play:hover { background: rgba(var(--jo-navy-rgb), .5); transform: scale(1.04); }

/**
 * Both icons occupy the same grid cell, so the control keeps its size and its
 * centre whichever face is showing and the swap costs no layout. The play
 * triangle is nudged right because its visual mass sits left of its box; the
 * pause bars are symmetrical and need no such correction.
 */
.jo-play__icon {
    grid-area: 1 / 1;
    display: grid;
    place-items: center;
    transition: opacity var(--jo-dur-fast) var(--jo-ease);
}

.jo-play__icon--play  { transform: translateX(2px); }
.jo-play__icon--pause { opacity: 0; }

/* Only a running player offers a pause. */
.jo-video.is-playing .jo-play__icon--play  { opacity: 0; }
.jo-video.is-playing .jo-play__icon--pause { opacity: 1; }

/* Without the Player API there is nothing to pause, so the control does not
   offer it — it would be a button that does nothing. */
.jo-video.is-fallback .jo-play { display: none; }

.jo-play__ring {
    position: absolute;
    inset: -1.5px;
    border-radius: 50%;
    border: 1.5px solid var(--jo-white);
    opacity: 0;
    pointer-events: none;
}

/**
 * The tooltip.
 *
 * The brief asks for this label not to sit permanently under the play button.
 * It appears on hover and on keyboard focus, and it is `role="tooltip"` wired to
 * the button with `aria-describedby`. On a touch device, where neither hover nor
 * focus happens, the control is still fully described by its own `aria-label`
 * and by the heading beside it — the tooltip is never the only explanation.
 */
.jo-play__tip {
    position: absolute;
    left: 50%;
    top: calc(50% + 52px);
    transform: translate(-50%, 4px);
    z-index: 2;
    padding: 7px 14px;
    border-radius: var(--jo-radius-pill);
    background: rgba(var(--jo-navy-rgb), .82);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    color: var(--jo-cream);
    font-size: var(--jo-body-sm);
    white-space: nowrap;
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--jo-tooltip-dur) var(--jo-ease),
                transform var(--jo-tooltip-dur) var(--jo-ease),
                visibility var(--jo-tooltip-dur);
}

.jo-play:hover ~ .jo-play__tip,
.jo-play:focus-visible ~ .jo-play__tip {
    opacity: 1;
    visibility: visible;
    transform: translate(-50%, 0);
}

/**
 * Starting playback.
 *
 * The cover and the control fade rather than vanish, and the player is faded up
 * underneath them, so the swap reads as one movement. Nothing is removed from
 * the flow: the stage holds its aspect ratio throughout, so the page does not
 * shift by a pixel when a video starts.
 *
 * The control fades but is never hidden outright: it stays focusable, so a
 * keyboard can always reach it and taking focus is what brings it back.
 */
.jo-video .jo-play,
.jo-video .jo-play__tip {
    transition: opacity var(--jo-dur) var(--jo-ease),
                visibility 0s linear var(--jo-dur),
                width var(--jo-dur) var(--jo-ease),
                height var(--jo-dur) var(--jo-ease),
                background-color var(--jo-dur) var(--jo-ease),
                transform var(--jo-dur) var(--jo-ease);
}

/**
 * While the video runs, the picture is left alone.
 *
 * The control fades out and comes back when the pointer is anywhere over the
 * video or the button takes keyboard focus — reachable by hand and by tab,
 * without sitting permanently over the middle of the picture.
 */
.jo-video.is-playing .jo-play { opacity: 0; }

.jo-video.is-playing .jo-play__tip {
    opacity: 0;
    visibility: hidden;
}

/*
 * Faded out, not hidden. `visibility: hidden` would take the button out of tab
 * order, and a control that can only be revealed by hovering is a control a
 * keyboard never reaches — so it stays focusable, and taking focus is one of
 * the two things that brings it back.
 */
.jo-video.is-playing .jo-video__controls:hover .jo-play,
.jo-video.is-playing .jo-play:focus-visible {
    opacity: 1;
    transition-delay: 0s;
}

/* The tooltip follows the control it belongs to, on the button's own hover. */
.jo-video.is-playing .jo-play:hover ~ .jo-play__tip,
.jo-video.is-playing .jo-play:focus-visible ~ .jo-play__tip {
    opacity: 1;
    visibility: visible;
}

/**
 * Touch has no hover to reveal anything with.
 *
 * So on a device that cannot hover, the control stays — but it steps out of the
 * centre and into the corner at a smaller size, which keeps it discoverable
 * without covering the picture it is controlling. Same ring, same blur, same
 * icon: one control treatment, placed differently where the input demands it.
 */
@media (hover: none) {
    .jo-video.is-playing .jo-play {
        position: absolute;
        left: var(--jo-play-dock-inset);
        bottom: var(--jo-play-dock-inset);
        width: var(--jo-play-size-docked);
        height: var(--jo-play-size-docked);
        opacity: 1;
        background: rgba(var(--jo-navy-rgb), .5);
    }

    /* Docked in the corner, the tooltip has nowhere sensible to sit and the
       button's own label already describes it. */
    .jo-video.is-playing .jo-play__tip { display: none; }
}

/**
 * The cover is a state, not a one-way door.
 *
 * It fades out when playback starts and fades back in on pause and on end, over
 * the panel's own navy rather than over a frozen video frame — the player is
 * faded out with it, so the two never show through one another. The player
 * itself is left mounted and holding its position the whole time, so this is a
 * change of appearance and not a reload.
 */
.jo-video.is-playing .jo-video__poster { opacity: 0; }

.jo-video__stage iframe,
.jo-video__stage video {
    opacity: 0;
    /* Faded out, the player must not still be catching clicks meant for the
       cover beneath it. Our control sits above this and keeps its own. */
    pointer-events: none;
    transition: opacity var(--jo-dur-slow) var(--jo-ease);
}

.jo-video.is-playing iframe,
.jo-video.is-playing video {
    opacity: 1;
    pointer-events: auto;
}

.jo-video__note {
    margin-top: var(--jo-space-4);
    padding: 12px 16px;
    border: 1px dashed var(--jo-pill);
    border-radius: var(--jo-radius-sm);
    background: var(--jo-surface);
    font-size: var(--jo-body-sm);
    color: var(--jo-muted);
}

/* ═══ §07 Finance ═════════════════════════════════════════════ */

.jo-finance__head {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 0.8fr);
    align-items: end;
    gap: var(--jo-space-6);
    margin-bottom: clamp(28px, 3vw, 44px);
}

.jo-finance__head .jo-eyebrow-pill { margin-bottom: var(--jo-space-4); }

.jo-finance__intro {
    color: var(--jo-soft);
    text-align: right;
    max-width: 46ch;
    justify-self: end;
}

/**
 * The calculator panel.
 *
 * A navy brand column and a light column for the embed. The container is here
 * and ready; the calculator itself is one setting away. Nothing about finance is
 * calculated by this website.
 */
.jo-finance__panel {
    display: grid;
    grid-template-columns: minmax(0, 0.34fr) minmax(0, 1fr);
    border-radius: var(--jo-radius-md);
    overflow: hidden;
    background: var(--jo-white);
    border: 1px solid var(--jo-border);
}

.jo-finance__brand {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--jo-space-5);
    padding: clamp(28px, 3vw, 48px);
    background: var(--jo-navy);
    color: var(--jo-cream);
}

.jo-finance__logo { width: clamp(130px, 12vw, 170px); height: auto; }

.jo-finance__brand-note {
    font-size: var(--jo-body-sm);
    color: rgba(var(--jo-cream-rgb), .78);
}

.jo-finance__embed {
    padding: clamp(20px, 2.2vw, 34px);
    min-height: 260px;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

/**
 * When the provider's calculator is framed here it brings its own branded
 * column with it, so the panel gives the whole width over to the frame and
 * drops the padding that would otherwise inset a page inside a page.
 */
.jo-finance__panel--framed { grid-template-columns: minmax(0, 1fr); }
.jo-finance__panel--framed .jo-finance__embed { padding: 0; min-height: 0; }

.jo-finance__frame {
    position: relative;
    width: 100%;
    /* A soft ground behind the frame so the swap from empty to loaded is not a
       white flash — it matches the calculator's own page colour. */
    background: #eaeef7;
}

/**
 * The frame's height.
 *
 * The calculator is cross-origin, so it cannot tell us how tall it is and we
 * cannot measure it. These heights are the provider's own measured content
 * height at each of its layout steps, rounded up: the page pins its footer to
 * the bottom of whatever height it is given, so a little too much shows a
 * clean margin, while too little would trap the calculator behind its own
 * scrollbar. Rounding up is therefore the safe direction, and the only one.
 */
.jo-finance__iframe {
    display: block;
    width: 100%;
    height: var(--jo-finance-h, 730px);
    border: 0;
}

/**
 * The provider's page re-stacks at 992, 768 and 576 pixels of frame width, and
 * needs 687, 1067, 1200 and 1215 pixels of height across those four bands.
 *
 * The breakpoints below are the viewport widths at which this page's container
 * actually hands the frame those widths — measured against the running site,
 * not derived from the container formula, because the gutter clamps at both
 * ends and the formula stops holding there. Each height carries about forty
 * pixels over the measured need, which lands as a margin above the provider's
 * own footer.
 */
@media (max-width: 1117px) { .jo-finance__frame { --jo-finance-h: 1110px; } }
@media (max-width: 865px)  { .jo-finance__frame { --jo-finance-h: 1245px; } }
@media (max-width: 649px)  { .jo-finance__frame { --jo-finance-h: 1260px; } }

.jo-finance__frame-fallback {
    padding: var(--jo-space-5);
    text-align: center;
    color: var(--jo-body);
}

.jo-finance__link-row {
    display: flex;
    justify-content: center;
    padding: var(--jo-space-5) var(--jo-space-4);
}

.jo-finance__panel--framed .jo-finance__link-row {
    border-top: 1px solid var(--jo-border);
    background: var(--jo-white);
}

.jo-finance__actions { justify-content: center; }

/* ═══ §08 CTA strip ═══════════════════════════════════════════ */

/**
 * The navy booking strip.
 *
 * Drawn as an inset panel on its own navy ground — the section supplies the
 * band, this supplies the slightly lighter card inside it, exactly as the design
 * has it.
 */
/**
 * The photograph behind a CTA band.
 *
 * Held a long way back — a low opacity, a navy wash over it and a gentle blur —
 * because its job is to give the panel something to sit above, not to be looked
 * at. The blur also means the crop barely matters, which is what lets one
 * photograph work at every width without a set of art-directed sources.
 *
 * The scrim is a separate layer rather than a filter on the image, so the
 * darkening is even across the whole band while the blur stays on the picture.
 */
.jo-section--has-backdrop { position: relative; isolation: isolate; overflow: hidden; }

.jo-section--has-backdrop > .jo-container,
.jo-section--has-backdrop > .jo-container-inner { position: relative; z-index: 1; }

.jo-cta-backdrop {
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
}

.jo-cta-backdrop__img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: var(--jo-focus, 50% 45%);
    opacity: var(--jo-cta-image-opacity, .16);
    filter: blur(var(--jo-cta-image-blur, 2px)) saturate(.85);
    /* Scaled slightly so the blur cannot pull the frame's edge into view. */
    transform: scale(1.06);
}

.jo-cta-backdrop__scrim {
    position: absolute;
    inset: 0;
    background: var(--jo-cta-scrim);
}

.jo-cta-strip {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: clamp(20px, 3vw, 48px);
    flex-wrap: wrap;
    padding: clamp(24px, 2.6vw, 40px) clamp(24px, 3vw, 52px);
    border-radius: var(--jo-radius-md);
    background: rgba(var(--jo-cream-rgb), .06);
    border: 1px solid var(--jo-line-on-navy);
}

/**
 * With a photograph behind it the panel becomes real glass: it blurs what it
 * covers instead of merely being a lighter rectangle. Without one the
 * backdrop-filter has nothing to act on and the panel looks exactly as it did,
 * so this needs no fallback of its own.
 */
.jo-section--has-backdrop .jo-cta-strip {
    background: rgba(var(--jo-cream-rgb), .10);
    backdrop-filter: blur(var(--jo-glass-blur, 14px)) saturate(1.1);
    -webkit-backdrop-filter: blur(var(--jo-glass-blur, 14px)) saturate(1.1);
    border-color: rgba(var(--jo-cream-rgb), .22);
}

.jo-cta-strip__copy { flex: 1 1 min(420px, 100%); }

.jo-cta-strip__title {
    font-family: var(--jo-font-display);
    font-size: var(--jo-h3);
    line-height: 1.15;
    font-weight: 500;
    color: var(--jo-cream);
}

.jo-cta-strip__text {
    margin-top: 6px;
    font-size: var(--jo-body-sm);
    color: var(--jo-on-navy);
}

.jo-cta-strip__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--jo-space-3);
}

/* The narrow inline prompt on treatment pages — the same idea on a light ground. */
.jo-inline-cta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: clamp(20px, 3vw, 48px);
    flex-wrap: wrap;
    padding: clamp(20px, 2.2vw, 30px) clamp(22px, 2.6vw, 40px);
    border-radius: var(--jo-radius-md);
    background: var(--jo-surface);
    border: 1px solid var(--jo-border);
}

.jo-inline-cta__title { font-size: var(--jo-body-lg); font-weight: 500; color: var(--jo-heading); }
.jo-inline-cta__text { margin-top: 4px; font-size: var(--jo-body-sm); color: var(--jo-soft); }
.jo-inline-cta__actions { display: flex; flex-wrap: wrap; gap: var(--jo-space-3); }

/* ═══ §09 Photographic CTA ════════════════════════════════════ */

/**
 * Full-width photography, a dark overlay and a central glass panel.
 *
 * The parallax is a transform on the media layer, driven against the section's
 * own progress through the viewport — not a fixed background, which cannot be
 * paced and misbehaves on iOS.
 *
 * The image layer is overscanned by 45% and anchored centrally, so a deliberately
 * dramatic drift still cannot bring a blank edge into the frame. The glass panel
 * is a sibling of the moving layer, not a child, so it never moves and stays
 * exactly as readable as it was drawn.
 */
.jo-photo-cta {
    position: relative;
    display: grid;
    place-items: center;
    min-height: clamp(420px, 34vw, 560px);
    padding-block: clamp(56px, 6vw, 96px);
    isolation: isolate;
    overflow: hidden;
    color: var(--jo-cream);
    background: var(--jo-navy);
}

.jo-photo-cta__media {
    position: absolute;
    inset: -22.5% 0;
    z-index: -2;
    will-change: transform;
}

.jo-photo-cta__img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.jo-photo-cta__scrim {
    position: absolute;
    inset: 0;
    /* A sibling of the media layer, not a child of it: -1 already sits above
       the picture (-2) and below the glass panel, which is in flow. */
    z-index: -1;
    background: var(--jo-photo-cta-scrim);
}

.jo-photo-cta__inner { width: 100%; }

.jo-glass {
    max-width: 520px;
    margin-inline: auto;
    padding: clamp(28px, 3vw, 44px) clamp(24px, 3vw, 40px);
    border-radius: var(--jo-radius-md);
    background: var(--jo-glass-bg);
    -webkit-backdrop-filter: var(--jo-glass-blur);
    backdrop-filter: var(--jo-glass-blur);
    border: 1px solid var(--jo-glass-border);
    text-align: center;
}

.jo-glass__eyebrow {
    border-color: rgba(var(--jo-cream-rgb), .45);
    margin-bottom: var(--jo-space-4);
}

.jo-glass__eyebrow span { color: rgba(var(--jo-cream-rgb), .9); }

.jo-glass__title { color: var(--jo-cream); margin-bottom: var(--jo-space-3); }

.jo-glass__text {
    color: rgba(var(--jo-cream-rgb), .88);
    font-size: var(--jo-card-body);
    line-height: 1.6;
}

.jo-glass__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--jo-space-3);
    margin-top: var(--jo-space-6);
}

/* ═══ §10 Contact ═════════════════════════════════════════════ */

.jo-contact {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    align-items: start;
    gap: clamp(20px, 2.2vw, 32px);
}

.jo-contact__details { gap: var(--jo-space-3); }

.jo-contact__address { font-size: var(--jo-card-body); color: var(--jo-body); }

.jo-contact__link {
    display: block;
    font-size: var(--jo-card-body);
    color: var(--jo-body);
    transition: color var(--jo-dur-fast) var(--jo-ease);
}

.jo-contact__link:hover { color: var(--jo-navy); }

.jo-contact__cta { margin-top: var(--jo-space-3); }

.jo-referral__note {
    margin-top: var(--jo-space-3);
    color: var(--jo-soft);
    font-size: var(--jo-body-sm);
}

.jo-referral__panel { margin-top: var(--jo-space-6); }

/* ═══ Responsive ══════════════════════════════════════════════ */

@media (max-width: 1000px) {
    .jo-split,
    .jo-lead,
    .jo-video-panel,
    .jo-contact,
    .jo-finance__head,
    .jo-finance__panel { grid-template-columns: minmax(0, 1fr); }

    /* Media first on a narrow screen, whichever side it was on. */
    .jo-split--media-right .jo-split__media,
    .jo-split--media-right .jo-split__copy { order: 0; }

    .jo-split__media,
    .jo-lead__media { max-width: 480px; margin-inline: auto; width: 100%; }

    .jo-finance__intro { text-align: left; justify-self: start; }

    .jo-hero__inner { flex-direction: column; align-items: flex-start; }
    .jo-hero--centre .jo-hero__inner { align-items: center; }

    /**
     * ── The clinician panel leaves the hero ──────────────────────────
     *
     * Stacked, the card used to drop to the bottom of the hero and sit on the
     * photograph, which pushed the hero past 1000px tall and left the heading
     * marooned at the top of a very deep picture. Below this width the hero
     * ends where a hero should end and the panel becomes the band underneath
     * it — a second hero band rather than a card floating on the first.
     *
     * The markup does not change. The hero becomes a two-row grid, its inner
     * wrapper goes `display: contents` so the copy and the panel become rows
     * of it, and the photograph is placed into row one — an absolutely
     * positioned grid child with a definite row is positioned against that
     * row's area rather than the padding box, so the picture stops exactly
     * where the band begins. One card, one set of clinician content, no
     * JavaScript.
     */
    .jo-hero--with-leads {
        display: grid;
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: minmax(var(--jo-hero-height-sub), auto) auto;
        min-height: 0;
        padding: 0;
    }

    .jo-hero--with-leads .jo-hero__inner { display: contents; }

    /*
     * Both ends of the row are named on purpose. For an absolutely positioned
     * grid child, an `auto` end resolves to the padding edge rather than to the
     * end of the row — so `grid-row: 1` alone would still stretch the
     * photograph over the band beneath it.
     */
    .jo-hero--with-leads .jo-hero__media { grid-row: 1 / 2; }

    /* The hero's own padding moves here, because the hero no longer has any. */
    .jo-hero--with-leads .jo-hero__copy {
        grid-row: 1;
        align-self: end;
        max-width: none;
        padding: calc(var(--jo-admin-bar) + var(--jo-header-height) + clamp(36px, 5vw, 90px))
                 var(--jo-gutter)
                 clamp(40px, 6vw, 72px);
    }

    /* The band. Navy, so it reads as the hero continuing rather than as a
       stray card dropped onto the white page below it. */
    .jo-hero--with-leads .jo-hero__leads {
        grid-row: 2;
        width: 100%;
        max-width: none;
        align-self: stretch;
        background: var(--jo-navy);
        padding: clamp(24px, 5vw, 40px) var(--jo-gutter);
    }

    /*
     * On its own ground the card stops being a card: there is no photograph
     * behind it for the glass to work against, so the tint, blur and hairline
     * come off and the contents sit directly on the band.
     */
    .jo-hero--with-leads .jo-leads-card {
        /* No glass and no padding here, so there is no nested pair left to be
           concentric with: the inset the corner is derived from goes to zero
           along with the surface it belonged to. */
        --jo-leads-card-inset: 0px;
        --jo-leads-card-border: 0px;

        background: none;
        border: 0;
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
        padding: 0;
        max-width: var(--jo-container);
        margin-inline: auto;
        display: grid;
        grid-template-columns: minmax(0, 150px) minmax(0, 1fr);
        gap: clamp(18px, 4vw, 32px);
        align-items: center;
    }

    .jo-hero--with-leads .jo-leads-card__media { margin-bottom: 0; }
    .jo-hero--with-leads .jo-leads-card__body   { display: grid; justify-items: start; }
    .jo-hero--with-leads .jo-leads-card__cta    { width: auto; }
}

@media (max-width: 760px) {
    .jo-cta-strip,
    .jo-inline-cta { flex-direction: column; align-items: flex-start; }

    .jo-cta-strip__actions,
    .jo-inline-cta__actions { width: 100%; }

    .jo-cta-strip__actions .jo-btn,
    .jo-inline-cta__actions .jo-btn { flex: 1 1 auto; }

    .jo-video-panel { gap: var(--jo-space-6); }

    /* The tooltip has no hover to respond to here, so the label sits under the
       button permanently rather than being unreachable. */
    .jo-play__tip {
        opacity: 1;
        visibility: visible;
        transform: translate(-50%, 0);
    }
}

@media (max-width: 560px) {
    .jo-glass { max-width: none; }
    .jo-glass__actions .jo-btn { width: 100%; }
    .jo-hero__actions .jo-btn { flex: 1 1 auto; }
    .jo-accred { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/**
 * Touch and coarse pointers.
 *
 * A device with no hover has no way to reveal a hover-only tooltip, so the label
 * is permanent there — the same reasoning as the narrow-screen rule above, but
 * keyed on the actual capability rather than on width.
 */
@media (hover: none) {
    .jo-play__tip {
        opacity: 1;
        visibility: visible;
        transform: translate(-50%, 0);
    }
}
